How do you update a DateTime on SQL Server 2012 preserving milliseconds using Delphi 7 ADOQuery.ExecSQL
?
SQL server seems to drop the seconds precision so I do not have milliseconds or microseconds on a SQL Server 2012 DateTime2[7]
field. MS Access does not drop the milliseconds with this ADO Query. The following ADOQuery code seems to work with all DataTypes that I care about except SQL Server DateTime
.
The connection string I am using is:
Provider=SQLNCLI11.1;Integrated Security=SSPI;User ID="";Initial File Name="";Server SPN="";Data Source=myPC\SQLSERVER2012EXP;Initial Catalog=MyDatabase
Here is my code:
function ExecuteNonQry(Conn:TADOConnection;Sql:string;Params:Variant): Integer;
{ Execute a query that does not return a recordset. Returns number of rows
affected. Params can be any unique name, they are all dealt with in order
of appearance in the parameter array and in the sql string.
E.g. SQL
'INSERT INTO customers (id,name,country) VALUES (:id,:name,:country)';
E.g. calling code:
sql :=
'INSERT INTO Sessions (SessionType_cod , HasErrors, Start_Timestamp) ' +
' VALUES (:1, :2, :3)';
params := VarArrayOf([ 1, true, Now ]);
ExecuteNonQry( GvConnection1, sql, params );
Note: Do not use ADO with Paradox - will be slow and possibly error prone.
Tested the following DataTypes with "Insert Into" and "Update" queries
**********************************************************************
Delphi MS Access SQL Server Paradox
-----------------------------------------------------
ftInteger Long int
ftString Text(255) nvarchar(255)
ftString Memo nvarchar(max)
ftBoolean Boolean bit
ftDateTime Date datetime2(7)
ftDouble Double float
}
var
qry : TADOQuery;
begin
assert( Conn <> nil);
assert( Sql <> '');
qry := TADOQuery.Create(nil);
qry.DisableControls;
qry.SQL.Text := Sql;
AddParametersToQuery(qry, Params);
qry.Connection := Conn;
result := qry.ExecSQL;
end;
procedure AddParametersToQuery(var Qry: TADOQuery; Params: Variant);
{ Version 1b. (Uses Delphi function to replace "DIRegEx" dependencies)
Add parameters (type and value) to ADO query. ADOQuery must have SQL
text set and Params is a variant array.
Limitations: SQL Server drops DateTime second precision digits for
milliseconds or microseconds.
E.g. Sql:
'INSERT INTO Sessions (SessionType_cod , HasErrors, Start_Timestamp)
VALUES (:1, :2, :3)';
or Sql:
'INSERT INTO Sessions (SessionType_cod , HasErrors, Start_Timestamp)
VALUES (:mykey, :HasErrors, :myDateTime)';
}
const
regPattern = ':';
var
str: String;
val: Variant;
i: Integer;
sl: TStrings;
begin
assert( Qry.SQL.Text <> '');
// in some cases this is necessary.
Qry.Parameters.ParseSQL(Qry.SQL.Text, true);
sl := TStringList.Create;
try
// find all param wordssql text such as '1, 2, 3'
sl := ExtractWordsToStrings(':', Qry.SQL.Text);
// loop through any matches found
for i := 0 to sl.Count -1 do
begin
str := sl[i];
val := GetVarParam(i, Params);
// in some cases this is necessary.
Qry.Parameters.ParamByName(str).DataType :=
VarTypeToDataType(Ord(VarType(val)) );
Qry.Parameters.ParamByName(str).Value := val;
end;
finally
sl.Free;
end;
end;
UPDATED
Modified code for MS Access and SQL Server:
if (VarType(val) = varDate) And IsSqlServerProvider(Conn.Provider) then begin
// needed for SQL Server
Qry.Parameters.ParamByName(str).Value :=
FormatDateTime('yyyymmdd hh:nn:ss.zzz', val)
end
else
begin
// in some cases this is necessary.
Qry.Parameters.ParamByName(str).DataType :=
VarTypeToDataType(Ord(VarType(val)));
Qry.Parameters.ParamByName(str).Value := val;
end;
DateTime2(7) via Ado is seen as TWideStringField.
Datetime will be seen as TDateTimeField.
Internal conversion if assigning a TDatetime will ignore milliseconds like DateTimeToStr(dt).
You can handle this by using own conversion to WideString.
Function MyDateTimeString(d:TDateTime):String;
begin
Result := FormatDateTime('yyyymmdd hh:nn:ss.zzz',d);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
dt:TdateTime;
begin
dt := now;
Caption := FormatDateTime('dd.mm.yyyy hh:nn:ss.zzz',dt);
Adoquery1.Paramcheck := true;
Adoquery1.SQL.Text := 'Insert into Tab (a,b,DT) Values (:a,:b,:DT)';
Adoquery1.Parameters.ParseSQL(Adoquery1.SQL.Text,true);
Adoquery1.Parameters.ParamByName('a').Value := 1;
Adoquery1.Parameters.ParamByName('b').Value := 2;
Adoquery1.Parameters.ParamByName('DT').Value := MyDateTimeString(dt);
Adoquery1.ExecSQL;
end;
using then following will lead to rounding:
Adoquery1.Parameters.ParamByName('DT').DataType := ftDateTime;
Adoquery1.Parameters.ParamByName('DT').Value := dt;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With