【问题标题】:query works on sql server management studio 2008 but not in delphi查询适用于 sql server management studio 2008,但不适用于 delphi
【发布时间】:2026-01-31 11:50:01
【问题描述】:

我正在开发一个程序来使用 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;

然后我发现它只在更新日期类型字段时触发错误。我已经开发了其他程序来使用类似的查询更新不同的表,它工作正常。我尝试关闭项目并重新打开它,但它仍然给我那个错误消息。请告诉我我该怎么做..

【问题讨论】:

  • 一定要用参数。但请注意,'mm/dd/yyyy' 不是可靠的格式(它可以切换月份和日期)。以后使用“yyyymmdd”。
  • 哦?我可以在 sql server 中编辑日期格式吗?我使用 mm/dd/yyyy 是因为我认为这是 sql server 中用于日期时间的格式?
  • 不。不是一个有效的假设。
  • 'yyyymmdd' 是 iso,所以应该可以安全使用。

标签: sql-server-2008 delphi


【解决方案1】:

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

  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;

【讨论】:

  • Bummi,也许添加一个事实,即在设置 SQL 文本之前必须将 Adoquery.ParamCheck 设置为 True
  • @whosrdaddy 谢谢,确实会让它更舒服。 Adoquery.ParamCheck 默认为 true,您可以将其与 Adoquery.ParamCheck:=false 一起使用并自行执行:Adoquery1.Parameters.ParseSQL(Adoquery1.SQL.Text,true); Adoquery1.Parameters.ParamByName('df').DataType := ftDateTime; ......
  • Bummi - 我认为 ID 应该是 (var)char,不需要 StrToInt
【解决方案2】:

我想通了! (更像是,我的同事做了)

显然,在将 FormatDateTime('mm/dd/yyyy' 替换为 datetostr 并将 shortdateformat 设置为 'mm/dd/yyyy' 后,查询工作正常。但我想知道为什么会这样?我认为这些命令可以一样的吗?

【讨论】:

  • 不要这样做。按照 Bummi 说的做。
  • 不同的可能是你没有设置DateDelimiter,只有ShortdateFormat
  • 这是因为没有格式设置的 DateToStr 使用您本地化的机器设置,而您的数据库可能会或可能不喜欢该格式。使用 FormatDateTime('yyyymmdd',... 消除歧义:考虑 03 年 1 月 2 日,对于世界上的某些人来说,这是 2003 年 1 月 2 日,但对于其他人来说,这是 2003 年 2 月 1 日,甚至有些人会说 2001 年 2 月 3 日。 YYYYMMDD 是通用的。20030201 始终是 2003 年 2 月 1 日。