3

我正在运行一个通过 FireDAC 连接的 IB 数据库。

以下动态查询有效:

INSERT INTO RELATIONS (C_ID, M_ID, A_ID)
SELECT c.C_ID, 0, a.A_ID
FROM CATEGORIES c, ACTIONS a
WHERE c.NAME = :CATEGORY AND a.NAME = :ACTION

A_INDEX我在 RELATIONS (Integer) 中添加一列。对于本专栏,我想提供一个参数,所以我这样做:

INSERT INTO RELATIONS (C_ID, M_ID, A_ID, A_INDEX)
SELECT c.C_ID, 0, a.A_ID, :A_INDEX
FROM CATEGORIES c, ACTIONS a
WHERE c.NAME = :CATEGORY AND a.NAME = :ACTION

然而,这不起作用。出于某种原因,当我执行查询时,它抱怨CATEGORYparam 存在转换错误。

这是此查询操作的完整代码:

  procedure Test;
  var
    Query: TFDQuery;
  begin
    Query := TFDQuery.Create(nil);
    try
      Query.Connection := DBDataModule.dbMain;
      Query.ResourceOptions.ParamCreate := False;

      Query.SQL.BeginUpdate;

      Query.SQL.Add('INSERT INTO RELATIONS (C_ID, M_ID, A_ID, A_INDEX)');
      Query.SQL.Add('SELECT c.C_ID, 0, a.A_ID,:A_INDEX');
      Query.SQL.Add('FROM CATEGORIES c, ACTIONS a');
      Query.SQL.Add('WHERE c.NAME = :CATEGORY AND a.NAME = :ACTION');

      Query.SQL.EndUpdate;

      Query.Params.CreateParam(TFieldType.ftInteger, 'A_INDEX', ptInput);
      Query.Params.CreateParam(TFieldType.ftFixedWideChar, 'CATEGORY', ptInput);
      Query.Params.CreateParam(TFieldType.ftFixedWideChar, 'ACTION', ptInput);
      Query.ParamByName('CATEGORY').Size := 255;
      Query.ParamByName('ACTION').Size := 255;

      Query.Prepare;

      Query.ParamByName('A_INDEX').Value := 0;
      Query.ParamByName('CATEGORY').Value := 'Foo';
      Query.ParamByName('ACTION').Value := 'Foo';

      Query.ExecSQL; // <-- Exception
    finally
      Query.Free;
    end;    
  end;

在此处输入图像描述

我仍在学习 SQL、数据库和 FireDAC,所以我真的不明白为什么它允许我在 select 语句中输入直接值,但参数是不行的。

A_INDEX我还能如何使用第一个查询将参数动态插入到列中?

4

2 回答 2

2

您不能像这样对查询进行参数化:

INSERT INTO RELATIONS (C_ID, M_ID, A_ID, A_INDEX)
SELECT c.C_ID, 0, a.A_ID, :A_INDEX
FROM CATEGORIES c, ACTIONS a
WHERE c.NAME = :CATEGORY AND a.NAME = :ACTION

特别是它的SELECT表达式:

SELECT c.C_ID, 0, a.A_ID, :A_INDEX

克服这种情况的唯一方法是预处理器宏,但它们不能作为真正的查询参数工作,因为它们会修改 SQL 命令,因此 DBMS 必须再次准备命令。

例如:

procedure Test;
var
  Query: TFDQuery;
begin
  Query := TFDQuery.Create(nil);
  try
    Query.Connection := DBDataModule.dbMain;

    Query.SQL.Add('INSERT INTO RELATIONS (C_ID, M_ID, A_ID, A_INDEX)');
    Query.SQL.Add('SELECT c.C_ID, 0, a.A_ID, &A_INDEX'); // ← & defines macro
    Query.SQL.Add('FROM CATEGORIES c, ACTIONS a');
    Query.SQL.Add('WHERE c.NAME = :CATEGORY AND a.NAME = :ACTION');

    Query.ParamByName('CATEGORY').Value := 'Foo';
    Query.ParamByName('ACTION').Value := 'Foo';
    Query.MacroByName('A_INDEX').AsIdentifier := '0';

    Query.ExecSQL;
  finally
    Query.Free;
  end;    
end;

但是,如果该A_INDEX字段值应该是自动增量值,请像这样创建它。或者,如果它是来自另一个表的值,请在查询中加入该表。宏不能用作真正的命令参数,并且在插入许多需要准备好的命令的记录时可能效率低下。

于 2017-06-28T23:35:37.927 回答
0

可能你在 DFM 中设置了 SQL(直接在组件中),你可以在组件的 Params 属性中看到创建的参数。删除所有参数或手动添加 A_INDEX(整数,输入)。

我强烈建议您在源代码中创建参数并将属性 ParamCreate 设置为 false。如果您知道需要手动创建,则可以轻松控制它。

要手动创建参数,请使用 CreateParam 方法(在 TParams 类中)。

于 2014-08-27T13:17:30.493 回答