dbExpress的TSQLQuery可以使用吗?作为参数?

时间:2012-02-14 04:54:01

标签: delphi dbexpress

我们已将代码移植到Delphi XE2,并且需要将我们的数据访问组件从不再业务的第三方ODBCExpress更改为dbExpress的TSQLQuery。

我们有参数化的SQL查询,例如:

sSQL :=
  'UPDATE ZTestData SET '+
  ' StringField =?, '+
  ' IntField = ?, '+
  ' DecimalField = ?, '+
  ' BooleanField = ?, '+
  ' DateTimeField = ?, '+
  ' TextField = ? '+
  ' WHERE UniqueID = 3';

如果我们使用以下代码:

var
  qry:TSQLQuery;
begin
  qry.Close;
  qry.SQL.Text := sSQL;
  ShowMessage(IntToStr(qry.Params.Count));
end;

它返回0,所以我们无法使绑定工作,但如果我们将sSQL更改为:

sSQL :=
  'UPDATE ZTestData SET '+
  ' StringField =:Param1, '+
  ' IntField = :Param2, '+
  ' DecimalField = ?, '+
  ' BooleanField = ?, '+
  ' DateTimeField = ?, '+
  ' TextField = ? '+
  ' WHERE UniqueID = 3';

它返回2.

将所有SQL查询更改为新参数语法将是一件很麻烦的事。无论如何TSQLQuery都能识别出来吗?语法?

我看到DBXCommon.TDBXCommand使用了?语法:

http://www.andreanolanusse.com/en/parameterized-queries-with-dbexpress-dbx-framework/

但这意味着抛弃使用TSQLQuery的代码。解决此问题的最快捷/最简单的方法是什么?无论如何,TSQLQuery和TDBXCommand之间的区别在于什么与我有关?

3 个答案:

答案 0 :(得分:8)

我认为最快的方法是使用将实现此功能的类助手,如:

type
  TMyParamsHelper = class Helper for TSQLQuery
  public
    function SetupParams(AParamList: array of Variant): Boolean; overload;
    function SetupParams(ASQL: string; AParamList: array of Variant): Boolean; overload;
  end;

// implementation

function TMyParamsHelper.SetupParams(AParamList: array of Variant): Boolean;
var
  Index: Integer;
begin
  // here you can process the SQL as text and replace each ?
  // with :paramINDEX
  // first occurence of ? will be :param0, second will be :param1, etc.
  // implement your replace algorithm before the "for loop"
  for Index := Low(AParamList) to High(AParamList) do
    ParamByName(Format(':param%d', [Index])).AsVaraint := AParamList[ Index ];
  // of course you need to do it in a try...except block and return TRUE|FALSE
end;

function TMyParamsHelper.SetupParams(ASQL: string; AParamList: array of Variant): Boolean;
begin
  SQL.Text := ASQL;
  Result := SetupParams( AParamList );
end;

所以现在你所要做的就是打电话:

...
ASQLQueryVariable.SetupParams([2012, 'Hello World', 2.14, 'It WORKS!']);
// or
ASQLQueryVariable.SetupParams(
  'UPDATE MyTable SET Year = ?, Title = ?, Cents = ?, Comment = ? WHERE <CLAUSE HERE>',
  [2012, 'Hello World', 0.02, 'It WORKS!']
);
...

注意:我正在写这篇文章,可能有拼写错误,可能不是最好的方法......

让我知道这对你有什么影响,我一直想要“?”而不是ParamByName,但实施它太懒了......

答案 1 :(得分:5)

非平凡的方法:

    来自TMyQuery
  • 子类TSQLQuery;
  • TMyQuery的构造函数中将TStringList(SQL).OnChange设置为您自己的QueryChanged方法。有关详细信息,请参阅SqlExpr.pas单元中的TSQLQuery.QueryChanged
  • 你需要用你自己的SetParamsFromSQL调用替换它,它将解析SQL文本并为每个'?'创建参数对象。 occurence。

更简单的方法:

  • 创建过程,将获得一个SQL字符串和Params集合;
  • 该过程将解析SQL文本并为每个'?'创建参数对象occurence;
  • TSQLQuery.ParamCheck设置为False,并在设置SQL属性后调用proc。

最后考虑使用3d派对解决方案,例如AnyDAC。它支持ODBC和'?'参数标记。

答案 2 :(得分:0)

我最终编写了一个方法,将查询中的问号转换为:param1样式参数。有趣的是,Delphi有一个DB.TParams.ParseSQL方法,可以将参数转换为问号。这种方法基本上与此相反。

function THstmt.AddParamsToSQL(const SQL: String): String;
var
  LiteralChar: Char;
  CurPos, StartPos, BeginPos: PChar;
  ParamCount:Integer;
begin
  //Locates the question marks in an SQL statement
  //and replaces them with parameters.
  //i.e. the reverse of DB.TParams.ParseSQL

  //This method is base on DB.TParams.ParseSQL

  //For example, given the SQL string
  //SELECT * FROM EMPLOYEES WHERE (ID = ?) AND (NAME = ?)

  //ParseSQL returns the string
  //SELECT * FROM EMPLOYEES WHERE (ID = :1) AND (NAME = :2)

  Result := '';

  ParamCount := 0;
  StartPos := PChar(SQL);
  BeginPos := StartPos;
  CurPos := StartPos;
  while True do
  begin
    // Fast forward
    while True do
    begin
      case CurPos^ of
        #0, '?', '''', '"', '`':
          Break;
      end;
      Inc(CurPos);
    end;

    case CurPos^ of
      #0: // string end
        Break;
      '''', '"', '`': // literal
      begin
        LiteralChar := CurPos^;
        Inc(CurPos);
        // skip literal, escaped literal chars must not be handled because they
        // end the string and start a new string immediately.
        while (CurPos^ <> #0) and (CurPos^ <> LiteralChar) do
          Inc(CurPos);
        if CurPos^ = #0 then
          Break;
        Inc(CurPos);
      end;
      '?': //parameter
      begin
        Inc(CurPos);
        Inc(ParamCount);
        Result := Result + Copy(SQL, StartPos - BeginPos + 1, CurPos - StartPos - 1) + ':' + IntToStr(ParamCount);
        StartPos := CurPos;
      end;
    end;
  end;
  Result := Result + Copy(SQL, StartPos - BeginPos + 1, CurPos - StartPos);
end;