在SQL Server Management Studio 2008中可以运行的查询在Delphi中无法运行。

4

我正在开发一个使用SQL Server更新表格字段的Delphi 7程序。程序如下:

sql := 'UPDATE tb_dt_contract SET '
      +' id_schedule = '+quotedstr(label_id_schedule.Caption)
      +',start_date = '+quotedstr(formatdatetime('mm/dd/yyyy',DateTime_start.Date))
      +',finish_date = '+quotedstr(formatdatetime('mm/dd/yyyy',DateTime_finish.Date))
      +',contract_location = '+quotedstr(uppercase(Edit_location.Text))
      +',sign_date = '+quotedstr(formatdatetime('mm/dd/yyyy',DateTime_sign.Date))
      +' WHERE id = '+quotedstr(label_id.Caption);
ADOQuery1.Close;
ADOQuery1.SQL.Text := sql;
ADOQuery1.ExecSQL;

当我运行程序时,它会给我一个错误:“'='附近的语法不正确”。但是当我使用showmessage查看查询并在sql server management 2008中运行它时,它可以正常工作。然后我尝试将查询拆分成以下几个部分:
SQL := 'UPDATE tb_dt_contract SET '
      +' id_schedule = '+QUOTEDSTR(label_id_schedule.CAPTION)
      +' WHERE id = '+quotedstr(label_id.Caption);
ADOQuery1.Close;
ADOQuery1.SQL.Text := sql;
ADOQuery1.ExecSQL;

SQL := 'UPDATE tb_dt_contract SET '
      +' start_date = '+quotedstr(formatdatetime('mm/dd/yyyy',DateTime_start.Date))
      +' WHERE id = '+quotedstr(label_id.Caption);
ADOQuery1.Close;
ADOQuery1.SQL.Text := sql;
ADOQuery1.ExecSQL;

SQL := 'UPDATE tb_dt_contract SET '
      +' finish_date = '+quotedstr(formatdatetime('mm/dd/yyyy',DateTime_finish.Date))
      +' WHERE id = '+quotedstr(label_id.Caption);
ADOQuery1.Close;
ADOQuery1.SQL.Text := sql;
ADOQuery1.ExecSQL;

SQL := 'UPDATE tb_dt_contract SET '
      +' contract_location = '+quotedstr(uppercase(edit_location.Text))
      +' WHERE id = '+quotedstr(label_id.Caption);
ADOQuery1.Close;
ADOQuery1.SQL.Text := sql;
ADOQuery1.ExecSQL;

SQL := 'UPDATE tb_dt_contract SET '
      +' sign_date = '+quotedstr(formatdatetime('mm/dd/yyyy',DateTime_sign.Date))
      +' WHERE id = '+quotedstr(label_id.Caption);
ADOQuery1.Close;
ADOQuery1.SQL.Text := sql;
ADOQuery1.ExecSQL;

我发现只有在更新日期类型的字段时才会触发该错误。我已经开发了其他程序来更新不同的表,使用类似的查询方式,而且它们正常运行。我尝试关闭项目并重新打开它,但仍然出现错误消息。请告诉我应该怎么做。


1
一定要使用参数。但请注意,“mm/dd/yyyy”不是一个可靠的格式(它可能会交换月份和日期)。将来请使用“yyyymmdd”。 - ErikE
哦?我可以在SQL Server中编辑日期格式吗?我使用mm/dd/yyyy,因为我认为这是datetime在SQL Server中使用的格式? - dapidmini
不好。这不是一个有效的假设。 - ErikE
'yyyymmdd' 是 ISO 格式,因此使用起来应该是安全的。 - Pieter B
2个回答

14

为了避免转换并创建独立于数据库的保存查询,您应该使用参数,如果多次使用,还可以加快操作速度。

  Adoquery1.SQL.Text := 'UPDATE tb_dt_contract SET finish_date=:df where WHERE id =:id';
  // in some cases it may be necessary to add  the three comented lines
  //Adoquery1.Parameters.ParseSQL(Adoquery1.SQL.Text,true);
  //Adoquery1.Parameters.ParamByName('df').DataType := ftDateTime;
  //Adoquery1.Parameters.ParamByName('id').DataType := ftInteger;
  Adoquery1.Parameters.ParamByName('df').Value :=DateTime_finish.Date;
  Adoquery1.Parameters.ParamByName('ID').Value :=StrToInt(label_id.Caption);
  Adoquery1.ExecSQL;

1
Bummi,也许可以加上这个事实:在设置SQL文本之前,必须将Adoquery.ParamCheck设置为True。 - whosrdaddy
@whosrdaddy 谢谢,确实会让它更舒适。 Adoquery.ParamCheck 默认为 true,您可以使用 Adoquery.ParamCheck:=false 并自行操作: Adoquery1.Parameters.ParseSQL(Adoquery1.SQL.Text,true); Adoquery1.Parameters.ParamByName('df').DataType := ftDateTime; ...... - bummi
Bummi - 我认为ID应该是(var)char类型,不需要使用StrToInt。 - Gerry Coll

-1

我搞定了!(更确切地说,是我的同事)

显然,在将FormatDateTime('mm/dd/yyyy'替换为datetostr并将shortdateformat设置为'mm/dd/yyyy'之后,查询正常工作。不过我想知道为什么呢?我以为这些命令做的是同样的事情?


1
不要这样做。按照Bummi所说的方式去做。 - Jan Doggen
可能的区别在于您没有设置日期分隔符,只设置了短日期格式。 - Jan Doggen
这是因为没有使用formatsettings的DateToStr会使用您本地化的机器设置,而您的数据库可能会或可能不喜欢该格式。使用FormatDateTime('yyyymmdd',...可以消除歧义:考虑01/02/03,对于世界上的某些人来说,这是2003年1月2日,但对于其他人来说是2003年2月1日,甚至有些人会说是2001年2月3日。YYYYMMDD是通用的。20030201始终是2003年2月1日。 - Pieter B

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接