我有以下SQL语句:
SELECT 420, DueDate, ISNULL(Amount, 0)
FROM Payments
WHERE CurveID = ? AND DueDate >= ?;
我正在使用Delphi 2010和TADODataset执行。语句正确执行,但条款DueDate >= ?
的评估不正确。如果我传入Date()
或Now()
作为第二个参数,我会在DueDate
字段中返回日期早于今天的值。
在SSMS中,如果我将日期参数替换为格式为“2011-09-09”的字符串,我可以成功运行此SQL查询:
SELECT 420, DueDate, ISNULL(Amount, 0)
FROM Payments
WHERE CurveID = 19 AND DueDate >= '2011-09-09';
然而,回到Delphi,即使我将参数值设置为此格式的日期的字符串化版本,我得到的结果也不正确(可能是因为TADODataset正确地将字符串转换回日期)。
我必须做什么,除了使用硬编码到SQL中的日期构建动态SQL以正确评估它?
答案 0 :(得分:2)
使用(命名)参数,例如
Query.CommandText := 'SELECT 420, DueDate, ISNULL(Amount, 0) FROM Payments '+
'WHERE CurveID = :CurveID AND DueDate >= :DueDate';
Query.Prepared := True;
Query.Parameters.ParamValues['CurveID'] := 19;
Query.Parameters.ParamValues['DueDate'] := EncodeDate(2011, 9, 9);
Query.Active := True;
这也允许您在系统不正确的情况下设置参数的类型,即
Query.Parameters.ParamByName('DueDate').DataType := ftDate;
另请注意,ADODataSet的ParamCheck属性必须为true
(默认)才能使用:name
样式参数。
答案 1 :(得分:0)
请试试这个:
AND DueDate >= CONVERT(datetime,?);
答案 2 :(得分:0)
Delphi客户端和SQL Server之间的区域设置是否不同?这可能导致返回无效日期。虽然我承认,如果在“9/9/2011”中月份=年份,那应该不重要。
我们使用法国加拿大C#客户端与美英数据库服务器通信时遇到了类似问题。客户端将2011年4月1日格式化为“1/4/2011”,数据库将其解释为2011年1月4日。
答案 3 :(得分:0)
零日期在OS和DB中不同,01/01/1900 v / s 30/12/1899。您需要+/- 2天,具体取决于选择/更新。
答案 4 :(得分:0)
以下是我的问题的解决方案:
我正在使用TADOCommand对数据库执行SQL(而不是TADODataset,因为我错误地在问题中写道,oops)。切换到TADOQuery解决了这个问题。这两个类之间的执行SQL接口是不同的,TADOQuery明确地查看数据集的Parameters属性以获取它的参数。 TADOCommand有一个Parameters属性,但也接受一个Parameter数组作为.Execute()方法的参数。
使用TQuery,我的参数输入正确,而不需要额外的努力。这适用于位置或命名参数。
答案 5 :(得分:0)
我注意到的是使用Delphi TDateTime值分配ParamByName和ParamValues之间的行为差异
var
MyDate: TDateTime
AdoQuery1.ParamByName('DueDate').AsDateTime := MyDate // works with US English
//vs
AdoQuery1.ParamValues['DueDate'] := MyDate // works with various date formats
当您的ShortDate设置为英语US时没有区别,但如果不是,则ParamByName不会对所有设置进行正确的转换。
ParamValues正确进行转换。我猜测变体的转换代码比Delphi TDateTime值和ADO DateTime值之间的转换“更好” - 这就是为什么我在我的应用程序中不再使用ParamByName。