2012-02-14 16 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和'?'參數標記。

相關問題