Why does "WHERE (Time_Stamp >= TDateTime-variable)" ignore fractional seconds? - sql

Using Delphi 6 and Microsoft SQL Server 2000.
I need to extract records where a TDateTime Field is > a passed TDateTime, "FromDate".
It fails as if the fractional part of the seconds of the passed TDateTime are always zero.
Debug printouts confirm that the fractions are there.
The WHERE part ignores the fraction part of :Fdate.
Assume the following 3 records:
Record 1: Time_Stamp is 1.2
Record 2: Time_Stamp is 1.4
Record 3: Time_Stamp is 1.6
The value 1.3 is then sent to the Query in :Fdate.
The resulting dataset returns ALL 3 records.
I expected only records 2 and 3 since 1.3 > 1.2
The 'Time_Stamp' field in database is a SQL 'datetime' field.
Everything works perfectly for integer seconds,
i.e. one record per second, or less often, when the decimal fraction is unimportant.
Can anyone point out where my error is?
The SQL statement is generated by code (shown below) as follows:
SELECT TOP 6 * FROM T_TransactionLog
INNER JOIN T_LookUp_TransTypes
ON T_TransactionLog.TransType = T_LookUp_TransTypes.TransType
WHERE (Time_Stamp >= :Fdate)
AND T_TransactionLog.TransType IN (
3,
4,
5
)
AND LockerNo < 60001
ORDER BY Time_Stamp ASC
The code is as follows:
Query.Connection := Sys_DB_Form.ADOConnection;
DataSource.DataSet := Query;
Query.SQL.Add('SELECT TOP ' + IntToStr(cNoTransactions) + ' * FROM
T_TransactionLog');
Query.SQL.Add('INNER JOIN T_LookUp_TransTypes');
Query.SQL.Add('ON T_TransactionLog.TransType =
T_LookUp_TransTypes.TransType');
Query.SQL.Add('WHERE (Time_Stamp ' + S_Condition + ' :Fdate)');
Query.SQL.Add('AND T_TransactionLog.TransType IN (');
Query.SQL.Add(IntToStr(ord(Apl_TrLog.ttEA)) + ',');
Query.SQL.Add(IntToStr(ord(Apl_TrLog.ttMO)) + ',');
Query.SQL.Add(IntToStr(ord(Apl_TrLog.ttMC)));
Query.SQL.Add(')');
Query.SQL.Add('AND LockerNo < ' +
IntToStr(Apl_Config.cLNoOfFirstgate));
if Locker <> 0 then
begin
Query.SQL.Add('AND LockerNo = ' + IntToStr(Locker));
end;
Query.SQL.Add(S_OrderBy);
Query.Parameters.FindParam('Fdate').Value := FromDate; // <<< Fail????
Query.SQL.SaveToFile(GetApplicationDataPath + 'Sql.txt');
try
Query.Open;
except
ShowMessage('Query open fail on ME Show Transaction log');
end;

Please chech the accuracy note for SQL Server datetime and time data types on MSDN
It is written that:
Accuracy Rounded to increments of .000, .003, or .007 seconds
This means
23:59:59.997
is OK
But
23:59:59.998
will be rounded to 23:59:59.997
And
23:59:59.999
will be rounded to 00:00:00 for the next day

Related

FireDAC: possibility to make query faster - Delphi

I use bind variables in Delphi and on the other side there is Oracle database with Database link (#dblink). When I build a SELECT statement without bind variables, it has no problem with performance. Only if I query SELECT statement with bind variables it takes very long (sometimes 1-2 hour). Is it possible in FireDAC to make the query faster without changing SQL-query? I need to use bind variables to avoid SQL injection.
This SQL is very Fast in Delphi:
SELECT
DLGH_START_D Datum,
TRUNC((d.DLGH_ENDE_D - d.DLGH_START_D) * 24 * 60)||' Min '||
TRUNC(MOD(((d.DLGH_ENDE_D - d.DLGH_START_D) * 24 * 3600), 60))||' Sek' Dauer
FROM
dialoghistory d
WHERE
d.DLGH_PARAMETER_C = 'Name of Parameter' AND <--
d.dlgh_funktion_c = 'SQLS' AND
d.DLGH_START_D > '01.02.2020' <--
order by 1
This SQL is very slow in Delphi:
SELECT
DLGH_START_D Datum,
TRUNC((d.DLGH_ENDE_D - d.DLGH_START_D) * 24 * 60)||' Min '||
TRUNC(MOD(((d.DLGH_ENDE_D - d.DLGH_START_D) * 24 * 3600), 60))||' Sek' Dauer
FROM
dialoghistory d
WHERE
d.DLGH_PARAMETER_C = :B_Name AND <--
d.dlgh_funktion_c = 'SQLS' AND
d.DLGH_START_D > :Datum <--
order by 1
---------------------------
//slow execution period , because of bind variables (1 h)
qry := TFDQuery.CreateSQL(Application, sSqlText_.Text);
with qry do begin
...
Param.AsString := value; //set value of bind variable
...
Open;
Table dialoghistory looks like this
My Solution:
tmpQuery := TFDQuery.Create(self); // Create Query
tmpQuery.Sql.Text := 'SELECT * FROM dlgHistory d where d.DLGH_PARAMETER = :par';
...
// Set Data Type, Param Type and Size yourself
with tmpQuery.Params do begin
Clear;
with Add do begin
Name := 'par';
DataType := ftString;
Size := 128;
ParamType := ptInput;
end;
end;
tmpQuery.Params[0].AsString := 'Value'; //assign a value
tmpQuery.Prepare;
tmpQuery.Open; //And it works perfect!

Same query but different result when ran in different database servers

I have a local environment running MariaDB server version 10.2.14 and a production environment running MariaDB server version 10.1.40.
When running a calculation based on the haversine formula to calculate distance between 2 geolocations, my local environment returns 0 as the result, but the prod environment returns null.
A sample query is below:
select (acos(cos(radians((41.480473))) * cos(radians(41.480473)) *
cos(radians((-81.630990)) - radians(-81.630990)) +
sin(radians((41.480473))) * sin(radians(41.480473))) * 3958.755
) as distance
The result should be zero because it is essentially trying to get the distance between 2 locations with the same geolocation info.
Can anyone shed some light why my prod environment is giving me a null value when running the above sample instead of zero?
The difference comes from rounding errors for the outmost acos-function. The other system may give you exactly 1 while the other system may give you bit over 1 due to rounding errors. Valid parameters for acos are from 1 is 0 and acos value > 1 is NULL.
You can use ROUND before the outmost acos and make the calculation a function for easier use:
create function f_distance_in_miles(
in_lat1 decimal(9,7),
in_long1 decimal(9,7),
in_lat2 decimal(9,7),
in_long2 decimal(9,7)
)
returns float
deterministic
begin
declare v_i real;
set v_i = cos(radians(in_lat1)) * cos(radians(in_lat2)) * cos(radians(in_long1)
- radians(in_long2))
+ sin(radians(in_lat1)) * sin(radians(in_lat2));
if (v_i<-1) then
set v_i = -1;
elseif (v_i>1) then
set v_i = 1;
end if;
return acos(v_i)*3958.755;
end
And then use it like:
select f_distance_in_miles(41.480473, -81.630990, 41.480473, -81.630990)

Bind Dates in SQL Tuning advisor

I'm trying to bind a date to a variable using Oracle SQL Developers SQL Tuning advisor, but it recognizes it as a VARCHAR2 and not a DATE. Is there a way to specify the data type of the parameters you bind?
SQL:
SELECT * FROM Actv
WHERE ActvId = :in_UserGrpCds AND ActvTime >= :in_FromDate AND ActvTime < :in_ThruDate
OFFSET :in_CurrRecordOffset FETCH NEXT :in_NextRecordOffset ROWS ONLY;
The in_ThruDate get's bound as a VARCHAR2 and it can't run the tune.
Bind Variables :
1 - (NUMBER):1091
2 - (NUMBER):0
3 - (VARCHAR2):07-21-2018
4 - (NUMBER):50000
5 - (VARCHAR2):08-21-2018
-------------------------------------------------------------------------------
ERRORS SECTION
-------------------------------------------------------------------------------
- ORA-00932: inconsistent datatypes: expected DATE got NUMBER
-------------------------------------------------------------------------------
We only bind strings/numbers/nulls so adjust your SQL to include the to_date:
SELECT * FROM Actv
WHERE ActvId = :in_UserGrpCds
AND ActvTime >= to_date(:in_FromDate ,'MM-DD-YYYY')
AND ActvTime < to_date(:in_ThruDate ,'MM-DD-YYYY')
OFFSET :in_CurrRecordOffset FETCH NEXT :in_NextRecordOffset ROWS ONLY;

Calculate value per day

I have Oracle table where I insert data about network upload and download speed.
CREATE TABLE AGENT_HISTORY(
EVENT_DATE DATE,
NETWORK_UP NUMBER,
NETWORK_DOWN NUMBER
)
I want to generate Bar chart for last 30 days and display total upload traffic per day(24 hours).
select * from AGENT_HISTORY where EVENT_DATE >= SYSDATE - 30;
The problem which I don't know how to solve is how I can calculate the traffic for each day from the column NETWORK_UP. The result of the query should be 30 days with total upload traffic for each day. Is this possible without PL/SQL procedure?
You can do a query like this to aggregate totals data for both the network_up and network_down columns per day.
select trunc(event_day,'day') event_date
,sum(network_up) tot_network_up
,sum(network_down) tot_network_down
from agent_history
where event_day >= trunc(sysdate,'day') - interval '30' day
group by trunc(event_day,'day');
You can do it without embbeding the query in PL/SQL stored code depending on what you use for front end, in java you could you use something like this
Statement stmt = null;
String schema_name = 'abc';
String query = "select trunc(event_day,'day') event_date," +
"sum(network_up) tot_network_up," +
"sum(network_down) tot_network_down " +
"from " + schema_name +".agent_history " +
"where event_day >= trunc(sysdate,'day') " +
"- interval '30' day " +
"group by trunc(event_day,'day')"
try {
stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
String event_data = rs.getString("EVENT_DATE");
int tot_network_up = rs.getInt("TOT_NETWORK_UP");
int tot_network_down= rs.getInt("TOT_NETWORK_DOWN");
.....
}
catch (SQLException e) {
.......
} finally {
......
}
With something like this you just execute pure SQL.
My guess is that you just want to aggregate the data. Something like
SELECT trunc(event_date),
sum(network_up) total_up,
sum(network_down) total_down
FROM agent_history
WHERE event_date >= trunc(sysdate) - 30
GROUP BY trunc(event_date)
If that is not what you want, it would be very helpful to post some sample data, expected output, etc.

Android Sqlite - Select the row which was inserted 1 hour before

Am working on Android Sqlite where I try to fetch the rows which are inserted 1 hour before.But its not returning any thing,I checked by cursor.count()
I tried with the following queries
String[] columns = new String[] { KEY_ID, KEY_CONTENT1, KEY_CONTENT2,
KEY_CONTENT3, KEY_CONTENT4, KEY_CONTENT5, KEY_CONTENT6};
cursor = sqLiteDatabase.query(MYDATABASE_TABLE, columns, KEY_CONTENT3 + "< " + "DATETIME('NOW', '-1 hours')", null, null, null, null);
AND another query
String selectRow = "select * FROM detail1 WHERE content3 < DATETIME('NOW', '-1 hours');";
Cursor cursor = sqLiteDatabase.execSQL(selectRow);
AND another query
String selectRow = "select * FROM detail1 WHERE content3 < DATETIME('NOW', '-1 hours');";
cursor = sqLiteDatabase.rawQuery(selectRow,null);
This Query Works for me
String selectRow = "select * FROM detail1 WHERE content3 > DATETIME('NOW', '-1 hours');";
Cursor cursor = sqLiteDatabase.execSQL(selectRow);
DATETIME('NOW', '-1 hours');"
This function returns time in this 2014-01-04,
and in data base 2014-01-04 10:24:21 have in this format. here only 2014 is getting compared not the complete date. better approch i would suggest go with epoch
try below query which will give you difference in terms of seconds
SELECT (strftime('%s','now')/60) - (strftime('%s',content3)/60);