I have a SQLite database that contains a table called "players". I can see in DB Browser that the data in the table is correct however when attempting to retrieve the data it seems to be returning a totally different value than what's in the database.
Value in DB: 76561198113034550
Value returned : 152768822
I'm getting the value with the following
qryPlayers.Close;
qryPlayers.SQL.Text := 'SELECT * FROM players';
qryPlayers.Open;
playerID := qryPlayers.FieldByName('steamid').Value; // .AsString returns the same value
Whats causing this and how can I fix it?
I just checked, what value the 4 lower bytes of 76561198113034550 have... And tadaaa, it is 152768822! So the upper 4 bytes are simply truncated.
Declare playerID as Int64, not Integer or Cardinal since those types only have 4 bytes in memory.
And for retrieving the value from the DB use qryPlayers.FieldByName('steamid').AsLargeInt.
Related
I have a CosmosDb and a Synapse workspace linked. Everything almost works using Synapse to create SQL views to the Cosmos data.
In Cosmos I have one data set with a property that is always a zero. I know it is actually a decimal because it is a price and future data is likely to contain decimal prices.
In Synapse I need to project this data into an SQL view where that column is correctly a decimal(19,4).
When I run an OpenRowSet query into the Cosmos data and attempt to specify the type for this property I get the following error.
select *
from OPENROWSET(
'CosmosDb',
'account=myaccount;database=myDatabase;region=theRegion;key=xxxxxxxxxxxxxxx',
[myCollection])
with (
[salesPrice] float '$.salesPrice')
as testQuery
I get the error:
Column 'salesPrice' of type 'FLOAT' is not compatible with external data type 'Parquet physical type: INT64', please try with 'BIGINT'.
Obviously a BIGINT here is going to fail as soon as I get a true decimal price.
I think the parquet type is getting set to BIGINT because in Cosmos all the values for this column are zero. I guess more generally it would be the same problem if the Cosmos property was all non-zero integers.
How can I force the type of salesPrice to be a decimal or float?
(I don't want to get side tracked here on float vs decimal for monetary values, I understand the difference; this error happens either way)
UPDATE
This problem manifests itself also in another way without specifying a schema with OPENROWSET.
In a new CosmosDb collection insert a document such as:
{
"myid" : 1,
"price" : 0
}
If I wait a minute or so I can query this document from Synapse with:
select *
from OPENROWSET(
'myCosmosDb',
'account=myAccount;database=myDatabase;region=myRegion;key=xxxxxxxxxxxxxxxxxxx',
[myCollection])
as testQuery;
and I get the expected results.
Now add a second document:
{
"myid" : 1,
"price" : 1.1
}
and re-run the query and I get the same error:
Column 'price' of type 'FLOAT' is not compatible with external data type 'Parquet physical type: INT64', please try with 'BIGINT'
Is there any way to work around or prevent these kinds of errors?
How about set the document like
{
"myid" : "1",
"price" : "1.1"
}
Using Delphi 10.2, SQLite and Teecharts. My SQLite database has two fields, created with:
CREATE TABLE HistoryRuntime ('DayTime' DateTime, Device1 INTEGER DEFAULT (0));
I access the table using a TFDQuery called qryGrpahRuntime with the following SQL:
SELECT DayTime AS TheDate, Sum(Device1) As DeviceTotal
FROM HistoryRuntime
WHERE (DayTime >= "2017-06-01") and (DayTime <= "2017-06-26")
Group by Date(DayTime)
Using the Field Editor in the Delphi IDE, I can add two persistent fields, getting TheDate as a TDateTimeField and DeviceTotal as a TLargeIntField.
I run this query in a program to create a TeeChart, which I created at design time. As long as the query returns some records, all this works. However, if there are no records for the requested dates, I get an EDatabaseError exception with the message:
qryGrpahRuntime: Type mismatch for field 'DeviceTotal', expecting: LargeInt actual: Widestring
I have done plenty of searching for solutions on the web on how to prevent this error on an empty query, but have had not luck with anything I found. From what I can tell, SQLite defaults to the wide string field when no data is returned. I have tried using CAST in the query and it did not seem to make any difference.
If I remove the persistent fields, the query will open without problems on an empty return set. However, in order to use the TeeChart editor in the IDE, it appears I need persistent fields.
Is there a way I can make this work with persistent fields, or am I going to have to throw out the persistent fields and then add the TeeChart Series at runtime?
This behavior is described in Adjusting FireDAC Mapping chapter of the FireDAC's SQLite manual:
For an expression in a SELECT list, SQLite avoids type name
information. When the result set is not empty, FireDAC uses the value
data types from the first record. When empty, FireDAC describes those
columns as dtWideString. To explicitly specify the column data type,
append ::<type name> to the column alias:
SELECT count(*) as "cnt::INT" FROM mytab
So modify your command e.g. this way (I used BIGINT, but you can use any pseudo data type that maps to a 64-bit signed integer data type and is not auto incrementing, which corresponds to your persistent TLargeIntField field):
SELECT
DayTime AS "TheDate",
Sum(Device1) AS "DeviceTotal::BIGINT"
FROM
HistoryRuntime
WHERE
DayTime BETWEEN {d 2017-06-01} AND {d 2017-06-26}
GROUP BY
Date(DayTime)
P.S. I did a small optimization by using BETWEEN operator (which evaluates the column value only once), and used an escape sequence for date constants (which, in real you replace by parameter, I guess; so just for curiosity).
This data type hinting is parsed by the FDSQLiteTypeName2ADDataType procedure that takes and parses column name in format <column name>::<type name> in its AColName parameter.
I have some experince with MySql, and am moving to Sqlite for the first time.
The Sqlite documentation for data types, section 1.2 states that
SQLite does not have a storage class set aside for storing dates
and/or times. Instead, the built-in Date And Time Functions of SQLite
are capable of storing dates and times as TEXT, REAL, or INTEGER
values
I would prefer an auto timestamp, but will live with having to pass it in every time if it will get my code working.
Followinf this question, I have declared my field as
`time_stamp` TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
However, it is not displaying anything on a DB ware grid.
I added an OnDrawCell() and thought that this might help:
var cellText : String;
cellValue : String;
dateTime : TDateTime;
begin
if ARow = 0 then
Exit;
cellValue := myGrid.Cells[ACol, ARow];
case ACol of
0: ; // invisibe column, do nothing
1: cellText := cellValue;
2: begin
dateTime := StrToDateTime(cellValue);
cellText := DateTimeToStr(dateTime);
end;
3: cellText := cellValue;
4: cellText := cellValue;
end;
myGrid.Canvas.FillRect(Rect);
myGrid.Canvas.TextOut(Rect.Left + 2, Rect.Top + 2, cellText);
where column 2 is my timestamp, but is apparently empty.
So, my question is, can anyone correct this code snippet, or show me a code example of how to declare an Sqlite column which defaults to the current timestamp and how to display that in a DB aware grid? I am happy enough to store a Unix timestamp, if that would help.
Btw, I am using XE7, FireDac with a TMS TAdvDbGrid.
[Update] As mentioned it a comment thread below (and as perhaps ought to have been mentioned originally), in this case I am generating some dummy data for testing porpoises using a TDateTime and IncSecond(startTime, delay * i). So, effectively, I am writing a TDateTime to that field, then I close/open the datasource and all other fields of the new row are shown, but not that one.
But, that actually digresses from my original, "please provide an example" question and turns it into a "please fix my code" question. An answer to either will make me very happy.
You are looking in the wrong place, your problem is in the dataset. It is a generic problem for all datasets that get their data from an external database.
Your query/dataset has a copy of the data in your database. It gets that copy from the database when it is opened or when you use it to update/insert records into the database. If the data in the database is changed some other way, your dataset will not have those changes until the changed record(s) are re-read. This applies to you, because the timestamp value is being set in database, not through the dataset. This can be accomplished by closing then opening the dataset.
With FireDAC, try setting the query's UpdateOptions .RefreshMode := rmAll. It has worked for me when there is a single table in the query, i.e. no joins.
I have a table with a field defined as nvarchar(100).
I just noticed if inserted a new record (an 200 string value for example) the query works and not throws any exception.
Is a SQLite 'feature'?
Usign SQLite 1.0.94 with Visual Studio 2010 / C# and SQLite v3 dabatabse.
SQLite doesn't recognize the limit you specified in statement, so it's not enforced.
In order to enforce it, you might need a statement like this:
CREATE TABLE t (f TEXT CHECK(LENGTH(f)<101));
So text with more than 100 characters cannot be inserted.
SQLite has a single unlimited TEXT datatype. See the documentation:
http://www.sqlite.org/datatype3.html#affname
Note that numeric arguments in parentheses that following the type
name (ex: "VARCHAR(255)") are ignored by SQLite - SQLite does not
impose any length restrictions on the length of strings, BLOBs or numeric
values.
I have a TableAdapter that is fetching rows from a stored procedure. For some reason, when there are no results, the TableAdapter returns an INT with value 0 instead of NULL. The stored procedure has NOCOUNT ON.
The problem with this is that I have a ListView in the frontend with an EmptyDataTemplate, which is not being shown. When I ran the query in Query Analyzer, I see that it is returning 0 instead of NULL.
The stored procedure has a simple 'SELECT * FROM WHERE ' with one INT parameter (NOT Output). Running it in Query Analyzer, I get no output, as expected.
What's going on?
Check the ExcuteMode property of the tableAdapter for the query. Be sure it is set to "Reader". There are 3 options for ExecuteMode:
Reader - Returns rows of data
Scalar - Returns single value
NonQuery - Returns an int with number of rows affected
Also check the Parameters Collection for a return value parameter. It should have properites AllowDBNull (true if you allow nulls), Direction (ReturnValue). This parameter should hold the results of your SP. In your example it would be null since there were no records returned.
It looks like the stored procedure is returning the result. All stored procedures return a result code. It's most likely this.