2012-02-14 2 views
5

Мы портируем код на Delphi XE2 и должны изменить наши компоненты доступа к данным от стороннего ODBCExpress, который больше не находится в бизнесе, TSQLQuery dbExpress.Может ли использовать TSQLQuery dbExpress? как параметры?

Мы параметризованные 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. Интересно, что 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; 
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

5

Нетривиальный подход:

  • subsclass TMyQuery от TSQLQuery;
  • в конструкторе TMyQuery комплект TStringList(SQL).OnChange к вашему QueryChanged метод. См. TSQLQuery.QueryChanged в блоке SqlExpr.pas для получения подробной информации, что он делает.
  • там вам нужно будет заменить SetParamsFromSQL вызов своим собственным, который будет анализировать текст SQL и создавать объект параметра для каждого '?' встречаемости.

Более простой подход:

  • создать процедуру, которым будет получить строку SQL и сбор Params;
  • процедура будет анализировать текст SQL и создавать объект параметра для каждого '?' встречаемости;
  • установить TSQLQuery.ParamCheck на False и вызвать proc после установки SQL.

В заключение рассмотрим использование решений для сторонних разработчиков, таких как AnyDAC. Он поддерживает ODBC и «?» маркеры параметров.

Смежные вопросы