Delphi :“参数对象定义不正确,提供的信息不一致或不完整,”

tsm1rwdh  于 2022-11-04  发布在  其他
关注(0)|答案(9)|浏览(270)

这是一个执行以下操作的函数:

  • 创建一个长度为8的随机令牌
  • 将该令牌插入数据库
  • 如果用户已有令牌,请更新它。
  • 如果用户没有令牌,请将其插入。
procedure createToken(BenuNr: integer);
var
  AQ_Query:       TADOQuery;
  strToken:       string;
  intZaehler:     integer;
  const cCharSet: string = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
begin
    //Random String as Token
    SetLength(strToken, 8);
  for intZaehler := 1 to 8 do
  begin
    strToken[intZaehler] := cCharSet[1+Random(Length(cCharSet))];
  end;
  //Inserts the Token into the Database
  with AQ_Query do
  begin
    try
      AQ_Query := TADOQuery.Create(nil);
      ConnectionString := strConnectionString;
      SQL.Text := 'if EXISTS(select * from TOKN where BENU_NR = :paramBenu_NR) begin update TOKN set TOKEN = :paramTOKEN where BENU_NR = :paramBenu_NR end else insert into TOKN (BENU_NR, TOKEN) values (:paramBENU_NR,:paramTOKEN)';
      Prepared := true;
      Parameters.ParamByName('paramBENU_NR').DataType := ftInteger;
      Parameters.ParamByName('paramTOKEN').DataType := ftString;
      Parameters.ParamByName('paramBENU_NR').Value := BenuNr;
      Parameters.ParamByName('paramTOKEN').Value := strToken;
      ExecSQL;    //<< Exception as stated in the title
    finally
      Free;
    end;
  end;
end;

执行这个命令会抛出标题中所述的异常。我将上面的示例删掉,瞧:没有例外了。不幸的是我不明白为什么?

procedure createToken();
var
  AQ_Query:     TADOQuery;
  strToken:     string;
  intZaehler:      integer;
  const cCharSet:  string = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
begin
    //Random String as Token
    SetLength(strToken, 8);
  for intZaehler := 1 to 8 do
  begin
    strToken[intZaehler] := cCharSet[1+Random(Length(cCharSet))];
  end;
  //Inserts the Token into the Database
  with AQ_Query do
  begin
    try
      AQ_Query := TADOQuery.Create(nil);
      ConnectionString := strConnectionString;
      SQL.Text := 'update TOKN set TOKEN = :paramTOKEN where BENU_NR = 1';
      Prepared := true;
      Parameters.ParamByName('paramTOKEN').DataType := ftString;
      Parameters.ParamByName('paramTOKEN').Value := strToken;
      ExecSQL;   //<< No more exception
    finally
      Free;
    end;
  end;
end;

似乎每个SQL只允许1个参数。我使用的是 Delphi 7和MSSQL Server 2005

您知道如何修复第一个代码块以使其正常工作吗?

khbbv19g

khbbv19g1#

要使这个工作,你必须在SQL子句中只使用一次每个参数。要多次使用同一个参数,只需用新的名称声明它。我不知道为什么会这样,但我知道这可能是相当烦人的。

guicsvcw

guicsvcw2#

我曾经有机会用编译器尝试过:)我必须在家里安装一个编译器。
虽然我仍然觉得您对WITH的使用不寻常,但它似乎确实工作正常。
我已经看到您在几种情况下遇到的错误:
1.尝试一次对一个连接运行多个查询(由于线程或计时器+ processMessages)
1.当ProcedureName不正确时,使用TADOStoredProc
1.有时,如果ADO无法解析查询,则在没有DB架构的情况下无法测试。
请注意,在SQL Server中不需要显式定义参数类型。这些参数类型由附加到SQL TStringList对象的OnChanged事件自动分配。
因此,最好是指派SQL.Text属性(如同您所做的),或者如果使用.Add('SELECT...'),则使用SQL.BeginUpdate/SQL.EndUpdate配对。
原文回复:

with AQ_Query do
  begin
    try
      AQ_Query := TADOQuery.Create(nil);
      ConnectionString := strConnectionString;

虽然这看起来可行,但在示例化对象之前引用它似乎有点奇怪。
AQ_Query应在with语句之前示例化:

AQ_Query := TADOQuery.Create(nil);
  with AQ_Query do
  begin
    try
      ConnectionString := strConnectionString;

最好还是不要使用WITH-这是自找麻烦。
同样要注意的是,对象的创建应该在try.. finally之前。正如所写的那样,你会得到一个编译器警告。不要忽略这些--它们可以帮助你写更好的代码。

nc1teljy

nc1teljy3#

虽然这个错误很有挑战性,但您可以充分诊断它,以确定您的查询是有效的。问题出在参数中。找出真正问题的最佳方法是在查询进入时让SQL Server Profiler追踪您的数据库。它会显示参数是如何解译的。请将该查询复制到文本编辑器中,以查看问题出在哪里。
如果您无法使用SQL Server Profiler,则应将值“BenuNr”和“strToken”输出到屏幕或控制台,以便您可以真正看到作为参数传入的内容。

pdkcd3nj

pdkcd3nj4#

直到现在,我都没有解决这个问题。
但我猜问题出在参数内部的某个地方以及如何访问它们。编译器通过索引来挑选它们,而不是像我假设的那样通过名称来挑选。
仔细查看OI中的TADOQuery组件(特别是在TParameters部分),您可以看到索引。
最后,可能需要首先添加一个参数,为它指定一个名称,然后插入一个值,或者类似这样的操作。

gpnt7bae

gpnt7bae5#

关闭准备。在ADO组件上设置prepared=False。服务器似乎在两个参数都存在之前就看到了它,并准备(编译)它。当您使用两个参数执行它时,参数列表与准备语句不匹配。

ryhaxcpt

ryhaxcpt6#

对OP来说比较晚,但对其他人来说可能有用。一个参数在sql语句中只能出现一次-这是ADO的限制。

select * from table where field1=:param or field2=:param

这不起作用。您可以使用两个不同的参数

select * from table where field1=:param1 or field2=:param2

或者使用嵌入式变量(如果后端是mssql:

declare @param int=:param
select * from table where field1=@param or field2=@param
o2g1uqev

o2g1uqev7#

哎哟。你刚刚碰到了我们的系统架构师在工作中称之为“有史以来最糟糕的错误”。这是一个非常普通的错误,可能意味着各种各样的事情。但我只在INSERT语句中看到过它,所以试着看看那里。它是由ADO得到的定义在某种程度上与数据库模式不匹配引起的。
尝试将查询缩减为只执行插入操作,并使用SQL Management Studio附带的SQL事件探查器来观察ADO在触发它时所执行的操作。它很可能会询问表的结构,并将其与语句的结构进行比较,最后发现结果并不理想,而且不会真正向数据库发送INSERT命令。
确保字段的数据类型正确,并且只使用这两个值就可以成功地在表中运行INSERT。这可能不起作用--毕竟,这 * 是 * 有史以来最糟糕的错误--但它应该为您提供一个起点。

vdzxcuhz

vdzxcuhz8#

您不需要指定DataType。成功调用Prepare;后,应根据服务器表定义正确配置参数。
我的猜测是,通过赋值DataType,参数可能被重置,并且丢失了一些信息,例如,ParamType应该是ptInput,但被重置为ptUnknown或类似的内容。
请尝试删除设置DataType的那些行,看看是否有帮助。

3vpjnl9f

3vpjnl9f9#

对我来说,这个错误没有参数,当SQL语句(否则完全有效)包含一个varchar文字值,在引用的子文本中有一个冒号(:)时。

UPDATE ... SET myfield = 'foo " :bar "'

解决方案可以是从丑陋的嵌入式文字切换到参数。我还没有找到其他合适的解决方案。

相关问题