2012-02-14 72 views
5

我们已将代码移植到Delphi XE2,并且需要将我们的数据访问组件从不再处于业务状态的第三方ODBCExpress更改为dbExpress的TSQLQuery。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之间有什么区别,关于什么与我有关?

回答

0

我写了一个方法将查询中的问号转换为:param1样式参数。有趣的是,德尔福有一个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; 
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!'] 
); 
... 

注:我M写这从我的头顶,可能有错别字,并可能不是最好的办法...

让我知道这是如何工作的你,我一直想要“?”在ParamByName,但代替懒得实现它...

+0

查看我的回答。 DB.TParams.ParseSQL是一种将参数转换为问号的方法,如果这是您想要去的路线。我更喜欢自己的ParamByName。 – Robo 2012-02-16 22:00:46

5

非平凡的方法:

  • subsclass TMyQueryTSQLQuery;
  • 构造函数TMyQueryTStringList(SQL).OnChange设置为您自己的QueryChanged方法。详细信息请参见SqlExpr.pas单元中的TSQLQuery.QueryChanged,它在做什么。
  • 那里你需要用你自己的代码调用SetParamsFromSQL,它会解析SQL文本并为每个'?'创建参数对象。 occurence。

更简单的办法:

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

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

相关问题