如何使用Delphi 7 ADOQuery.ExecSQL更新SQL Server上的DateTime,保留毫秒数?

use*_*064 8 delphi ado datetime2

如何使用Delphi 7更新SQL Server 2012上的DateTime,保留毫秒数ADOQuery.ExecSQL

SQL Server似乎降低了秒的精度,所以我在SQL Server 2012 DateTime2[7]字段上没有毫秒或微秒.使用此ADO查询,MS Access不会丢弃毫秒.以下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;
Run Code Online (Sandbox Code Playgroud)

更新

修改了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;
Run Code Online (Sandbox Code Playgroud)

bum*_*mmi 6

通过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;
Run Code Online (Sandbox Code Playgroud)

使用以下将导致舍入:

  Adoquery1.Parameters.ParamByName('DT').DataType := ftDateTime;
  Adoquery1.Parameters.ParamByName('DT').Value := dt;
Run Code Online (Sandbox Code Playgroud)