如何使用 Delphi 7 ADOQuery.ExecSQL 在 SQL Server 上更新 DateTime,保留毫秒?
Posted
技术标签:
【中文标题】如何使用 Delphi 7 ADOQuery.ExecSQL 在 SQL Server 上更新 DateTime,保留毫秒?【英文标题】:How to update a DateTime on SQL Server preserving milliseconds using Delphi 7 ADOQuery.ExecSQL? 【发布时间】:2012-12-26 07:24:58 【问题描述】:如何使用 Delphi 7 ADOQuery.ExecSQL
在 SQL Server 2012 上更新 DateTime 以保留毫秒?
SQL 服务器似乎降低了秒精度,因此我在 SQL Server 2012 DateTime2[7]
字段上没有毫秒或微秒。 MS Access 不会使用此 ADO 查询减少毫秒数。以下 ADOQuery 代码似乎适用于我关心的所有 DataTypes,除了 SQL Server DateTime
。
我使用的连接字符串是:
Provider=SQLNCLI11.1;Integrated Security=SSPI;User ID="";Initial File Name="";Server SPN="";Data Source=myPC\SQLSERVER2012EXP;Initial Catalog=MyDatabase
这是我的代码:
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;
更新
MS Access 和 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;
【问题讨论】:
要保留毫秒,您可以简单地使用 TDateTime 的本机类型声明数据库中的列:double。这将意味着获得 TFloatField,但 IIRC 他们有一个 AsDateTime 成员。 【参考方案1】:通过 Ado 的 DateTime2(7) 被视为 TWideStringField。 日期时间将被视为 TDateTimeField。 如果分配 TDatetime,内部转换将忽略 DateTimeToStr(dt) 等毫秒。 您可以使用自己的转换为 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;
使用 then 以下将导致四舍五入:
Adoquery1.Parameters.ParamByName('DT').DataType := ftDateTime;
Adoquery1.Parameters.ParamByName('DT').Value := dt;
【讨论】:
这确实适用于 SQL 服务器,谢谢!我希望 ParamByName 也适用于 MS Access。有什么想法让它对两者都有效吗?如果失败了,我想我将不得不通过解析连接字符串并相应地设置参数来确定连接的类型。我还没有找到一个很好的 ADO 枚举类型来查找您的连接类型,所以它是连接字符串... var i:Integer; begin for I := 0 to AdoConnection1.Properties.Count - 1 do begin Listbox1.Items.Add(AdoConnection1.Properties[i].Name+'='+VarToStr(AdoConnection1.Properties[i].Value)) end; Showmessage(AdoConnection1.Properties.Item['Provider Friendly Name'].Value );结尾; //或者更好地使用'Provider Name' 谢谢。 TADOConnection.Provider 属性中的“Provider Name”字符串运行良好。以上是关于如何使用 Delphi 7 ADOQuery.ExecSQL 在 SQL Server 上更新 DateTime,保留毫秒?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Delphi 在控制台应用程序中激活玻璃效果(Windows Vista/7)
如何使用 Delphi 7 ADOQuery.ExecSQL 在 SQL Server 上更新 DateTime,保留毫秒?
如何将字符串或信息发送到我在 Delphi 7 中使用 Createprocess 打开的进程