2012-02-14 10 views
5

Hemos transferido el código a Delphi XE2, y necesitamos cambiar nuestros componentes de acceso a datos de ODBCExpress de un tercero que ya no está en funcionamiento, a TSQLQuery de dbExpress.¿Puede el uso de TSQLQuery de dbExpress? como parámetros?

Hemos parametrizado consulta SQL tales como:

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

si usamos el siguiente código:

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

Devuelve 0, por lo que podemos conseguir los enlaces de trabajo, pero si cambiamos a sSQL:

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

devuelve 2.

Va a ser una gran molestia cambiar todas las consultas SQL a la sintaxis del nuevo parámetro. ¿Hay alguna forma para que TSQLQuery reconozca el? ¿sintaxis?

Veo que DBXCommon.TDBXCommand utiliza el? Sintaxis:

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

Pero significaría tirar nuestro código que utiliza TSQLQuery. ¿Cuál es la forma más rápida/más fácil de resolver esto? ¿Cuál es la diferencia entre TSQLQuery y TDBXCommand de todos modos, en términos de lo que es relevante para mí?

Respuesta

0

Terminé escribiendo un método para convertir signos de interrogación en la consulta a: parámetros de estilo param1. Curiosamente, Delphi tiene un método DB.TParams.ParseSQL que convierte los parámetros en signos de interrogación. Este método es básicamente un reverso de eso.

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

creo que el enfoque más rápido es el uso de ayudantes de clase que implementarán esta funcionalidad algo como:

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; 

Así que ahora todo lo que tiene que hacer es llamar:

... 
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!'] 
); 
... 

Nota: I' Estoy escribiendo esto en la cima de mi cabeza, podría tener errores ortográficos y podría no ser el mejor enfoque ...

Déjame saber cómo funciona esto para ti, siempre quise el "?" en lugar de ParamByName pero era demasiado perezoso para ponerlo en práctica ...

+0

Ver mi respuesta. DB.TParams.ParseSQL es un método que convierte los parámetros en signos de interrogación, si esa es la ruta que desea seguir. Yo prefiero ParamByName yo mismo. – Robo

5

enfoque no trivial:

  • subsclass TMyQuery de TSQLQuery;
  • en el constructor de TMyQuery establece TStringList(SQL).OnChange en su propio método QueryChanged. Consulte TSQLQuery.QueryChanged en la unidad SqlExpr.pas para obtener detalles sobre lo que está haciendo.
  • allí deberá reemplazar la llamada SetParamsFromSQL por la suya, que analizará el texto SQL y creará el objeto de parámetro para cada '?' ocurrencia.

Un enfoque más simple:

  • crear procedimiento, cosa que obtendrá una cadena SQL y recogida Parámetros;
  • el procedimiento analizará el texto SQL y creará el objeto de parámetro para cada '?' ocurrencia;
  • establece TSQLQuery.ParamCheck en False y llama al proc después de configurar la propiedad SQL.

Considere finalmente el uso de soluciones de terceros, como AnyDAC. Es compatible con ODBC y '?' marcadores de parámetros.

Cuestiones relacionadas