根据ADO提供商格式化日期

时间:2011-01-13 20:37:18

标签: sql-server delphi ms-access delphi-2010 ado

我有一个使用ADO的Delphi 2010应用程序来支持可以是SQL Server或MS Access的数据库。使用参数化查询将SQL发送到数据库时,可以正确处理日期表示中的差异。但我偶尔也需要形成动态SQL并将其发送到数据库。

有没有办法让我的日期的TADOConnection格式成为适合当前数据库的文本字符串,或者询问连接以了解我应该如何格式化日期?否则,我将无法构建提供程序名称和日期格式化函数的表。

4 个答案:

答案 0 :(得分:3)

您也应该能够使用动态sql参数。我已经在我自己的OPF框架的几个版本中完成了这个。

只需使用参数编写SQL语句,将其作为字符串分配给TAdoQuery(或TAdoCommand)的SQL文本。然后,组件应解析您的文本并为您设置参数集合。之后,您应该能够将值分配给参数并调用Open或Execute ...

给你一个想法:

  DS := DatasetClass.Create( self.Connection );
  try
    DS.QueryText := SQL.Text;
    FillSelectParams( DS );
    DS.Open;
    try
      ...
    finally
      DS.Close;
    end;
  finally
    DS.Free;
  end;

FillSelectParams调用以下FillParams过程:

procedure TSQLDataManager.FillParams(ADS: TCustomDataset);
var
  i: integer;
  ParamName: string;
  Attr: TCustomDomainAttribute;
  Ref: TCustomDomainObject;
  Value: Variant;
begin
  for i := 0 to ADS.ParamCount - 1 do begin
    Value := Null;
    ParamName := ADS.ParamName[i];
    if ParamName = 'Id' then begin
      ParamName := 'Identity';
    end;
    Attr := CDO.AttrByName[ParamName];
    if Attr <> nil then begin
      Value := ADS.AdjustParamValue( Attr );
    end else begin
      Ref := CDO.ReferenceByName[ParamName];
      if ( Ref <> nil ) and ( Ref.Identity <> C_UnassignedIdentity ) then begin
        Value := Ref.Identity;
      end;
    end;
    if Value <> Null then begin
      ADS.ParamValue[i] := Value;
    end;
  end;
end;

在这种情况下,参数值取自自定义域对象(CDO),但您可以在此处替换自己的风格。

AdjustParamValue函数负责几次转换。它已在所使用的TCustomDataSet类后代的ADO版本中实现,以处理具有不同TDataSet后代的组件变体,但SQL数据库类型无处可用:

function TADODCDataset.AdjustParamValue(Attr: TCustomDomainAttribute): Variant;
begin
  if Attr is TIdentityAttribute then begin
    if Attr.AsInteger = 0 then begin
      Result := Null;
    end else begin
      Result := Attr.Value;
    end;
  end else if Attr is TBooleanAttribute then begin
    if Attr.AsBoolean then begin
      Result := Integer( -1 );
    end else begin
      Result := Integer( 0 );
    end;
  end else if Attr is TDateTimeAttribute then begin
    if Attr.AsDateTime = 0 then begin
      Result := Null;
    end else begin
      Result := Attr.Value;
    end;
  end else if Attr is TEnumAttribute then begin
    Result := Attr.AsString
  end else begin
    Result := Attr.Value;
  end;
end;

答案 1 :(得分:2)

拉里,我会给你一个SQL Server部分的答案。

您可以使用sys.syslanguages系统视图获取有关sql server中安装的语言的信息,此视图返回的列之一称为dateformat,表示日期顺序,例如, DMY。

还使用@@langid(返回当前正在使用的语言的本地语言标识符(ID)。)函数,您可以编写类似这样的函数来获取Sql Server使用的当前日期格式。

select dateformat from sys.syslanguages  where langid=@@langid

所以现在你将有一个字符串,你可以在delphi中解析它来格式化你的日期。

另一个选择是选择一种预定义的SQL Server格式,并使用SQL语句中的CONVERT函数将字符串转换为日期。

检查此样本使用ISO格式进行转换

//The ISO  format is yyyymmdd so i can use the FormatDateTime function to convert any TdateTime to a Iso format sdatetiem string
DateStr:=FormatDateTime('YYYYMMDD',Now);
//Now construct the sql server sentence
SqlSentence:=Format('UPDATE MyTable SET DateField=CONVERT(DATETIME,%s,112)',QuotedStr(DateStr));

答案 2 :(得分:0)

尝试使用ODBC日期转义序列,SQL Server和Access OLEDB提供程序可能支持该序列。例如:

{d '2011-01-14'}

答案 3 :(得分:0)

正如Marjan建议的那样,你应该总是使用参数。 (尝试搜索SQL注入)

使用参数的另一个原因是查询计划可以在sql server上重用。 如果生成的第一个语句是来自客户的SELECT *&gt;'2010-12-21',并且生成的下一个州语言是来自客户的SELECT *,其中创建了&gt;'2010-12-22',则生成/编译查询优化器/计划两次(不同的声明)。但如果该语句两次都是SELECT *来自客户创建的&gt; ?,则重新使用该计划 - &gt; (稍微)降低SQL服务器上的压力。

我只是不是一个快速而肮脏的解决方案我尝试的所有SQL(实现)(我没有尝试Access)可以接受并理解ISO日期格式(例如'2010-12-21')