Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   SQL (https://www.clubdelphi.com/foros/forumdisplay.php?f=6)
-   -   Realizar un MERGE con los ADOConnection (https://www.clubdelphi.com/foros/showthread.php?t=87198)

bucanero 27-11-2014 13:51:55

Realizar un MERGE con los ADOConnection
 
Buenas,

Estoy intentando realizar un MERGE a una tabla en un servidor MSSQL a traves de los componentes ADO, en particular la consulta es

Código SQL [-]
merge STOCKS as target
using (values ('X3', '03', '2014-11-27', 'SA123', 3))  as source 
(EMPRESA,ALMACEN,FECHA,ARTICULO,UNIDADES)   on 
   target.empresa= source.empresa and 
   target.almacen=source.almacen and 
   target.fecha=source.fecha and 
   target.articulo=source.articulo
when matched then
    update
    set UNIDADES = source.UNIDADES
when not matched then
    insert (EMPRESA,ALMACEN,FECHA,ARTICULO,UNIDADES)
    values (
      source.EMPRESA,
      source.ALMACEN,
      source.FECHA,
      source.ARTICULO,
      source.UNIDADES,
    );

Pero siempre obtengo el error "Sintaxis incorrecta cerca de la palabra 'merge'"
He intentado ejecutarlo desde los componentes ADOCommandText, ADOQuery y directamente ejecutandolo con el ADOConnection.Execute siempre con el mismo resultado.

Dicha instrucción SQL es correcta y si la ejecuto en la aplicación Microsoft SQL Server Management Studio, se ejecuta sin problemas y obtengo los resultados esperados de inserción/actualización.

Esta consulta es en MSSQL es equivalente a hacer en MySQL un
Código SQL [-]
INSERT INTO .. ON DUPLICATE KEY UPDATE...

Comentar que estoy usando Delphi XE4, de servidor de datos MSSQL2005 y la conexión al servidor la realizo directamente a través de SQL NATIVE CLIENT.

También he intentando ejecutar dicha consulta con los componentes ZEOS, pero el resultado nuevamente ha sido el mismo.

Me da la impresión que el error al darlo en español lo este generando el SQL NATIVE CLIENT, pero ya lo actualice a la ultima versión del mismo, sin obtener ningún cambio.

Y buscando en google sobre este error tampoco he obtenido resultados.

Gracias anticipadas por su ayuda.

orodriguezca 27-11-2014 14:50:29

En general este tipo de sentencias de actualización no puede ejecutarse con el procedimiento "open" de un dataset o estableciendo "Active" a true, por lo que casi nunca se pueden ejecutar en tiempo de diseño. Con ADO asegúrate de estar utilizando el método TADOQuery.ExecSQL en el código de la aplicación.

Por otra parte, si mal no recuerdo, la sentencia merge está disponible desde la versión SQL Server 2008. Me sorprende que funcione en SQL Server 2005.

bucanero 27-11-2014 16:43:42

Hola orodriguezca, gracias por responder

En cuanto al servidor tenias razón, es la versión 2008, "Microsoft SQL Server 2008 (RTM) - 10.0.1600.22", es por eso que podía hacer el merge :rolleyes:

En cuanto a este tipo de sentencias, es cierto que no se pueden ejecutar con un SQLQuery, pero puestos a que no he conseguido ponerlo a funcionar ya he probado con todo :-). La forma de ExecSQL es de lo poco que me quedaba, pero no ha funcionado tampoco. Originalmente se deberia de ejecutar de esta forma, muy similar al ExecSQL, pero directamente sobre el componente CONNECTION, y la ejecución siempre sera en RUNTIME, dentro de un proceso de intercambio de datos con otras tablas.

Código:

    try
      ADOConnection1.Execute(
        'merge STOCKS as target' +
        'using (values (''X3'', ''03'', ''2014-11-27'', ''SA123'', 3))  as source' +
        '(EMPRESA,ALMACEN,FECHA,ARTICULO,UNIDADES) on ' +
        '  target.empresa= source.empresa and ' +
        '  target.almacen=source.almacen and ' +
        '  target.fecha=source.fecha and ' +
        '  target.articulo=source.articulo  and ' +
        'when matched then ' +
        '    update ' +
        '    set UNIDADES = source.UNIDADES ' +
        'when not matched then ' +
        '    insert (EMPRESA,ALMACEN,FECHA,ARTICULO,UNIDADES)' +
        '    values (' +
        '      source.EMPRESA,' +
        '      source.ALMACEN,' +
        '      source.FECHA,' +
        '      source.ARTICULO,' +
        '      source.UNIDADES' +
        '    );'
      );
    except
      On E:Exception do begin
        MessageDlg(E.Message, mtError, [mbOK], 0);
      end;
    end;

Aunque tras muchas pruebas, creo que el error no esta en los componentes, si no en la pasarela de conexión que realiza un preanalisis de la sentencia bloqueandola, y no dejandola llegar al motor de B.D., pues cuando intento esto mismo con los ZEOS el error y el comportamiento es exactamente el mismo.

¿Hay alguna forma de evitar este analisis previo y que le llegue al motor de BD?? para que en caso de error sea el propio motor el que de el error

orodriguezca 27-11-2014 17:17:37

Debería funcionar bien. Asegúrate que la aplicación se está conectando al servidor correcto. Hice una prueba con ADO y funcionó correctamente. Esto fue lo que hice:

Así establecí la cadena de conexión:

Código Delphi [-]
Provider=SQLNCLI10.1;Integrated Security=SSPI;Persist Security Info=False;User ID="";Initial Catalog=CRI_DESA;Data Source=Direccion_IP_del_Servidor;Initial File Name="";Server SPN=""

En ADOQuery1.SQL (En tiempo de diseño):
Código SQL [-]
MERGE PRUEBA1 as target
  using  PRUEBA2  AS SOURCE
  ON target.CAMPO1 = source.CAMPO1
 WHEN NOT MATCHED THEN 
   INSERT(CAMPO1) VALUES(source.CAMPO1);

Y como Acción:

Código Delphi [-]
procedure TForm14.Button1Click(Sender: TObject);
begin
  AdoQuery1.ExecSQL;
  ShowMessage('Prueba terminada');
end;

orodriguezca 27-11-2014 17:28:22

Revisando un poco más en detalle tu código creo que el problema puede estar en la concatenacion:

Código Delphi [-]
 ADOConnection1.Execute(
        'merge STOCKS as target' +
        'using (values (''X3'', ''03'', ''2014-11-27'', ''SA123'', 3))  as source' +
        '(EMPRESA,ALMACEN,FECHA,ARTICULO,UNIDADES) on ' +

Al concatenar la cadena quedaría como
Código Delphi [-]
 ADOConnection1.Execute('merge STOCKS as targetmerge STOCKS as targeusing (values (''X3'', ''03'', ''2014-11-27'', ....

Coloca al menos un espació al final de cada literal de cadena:
Código Delphi [-]
ADOConnection1.Execute(
        'merge STOCKS as target ' +
        'using (values (''X3'', ''03'', ''2014-11-27'', ''SA123'', 3))  as source ' +
        '(EMPRESA,ALMACEN,FECHA,ARTICULO,UNIDADES) on ' +
        '   target.empresa= source.empresa and ' +
        '   target.almacen=source.almacen and ' +

bucanero 27-11-2014 18:59:02

Gracias orodriguezca por tus respuestas.

Finalmente ya conseguí que funcionara, parece ser que se trataba de un problema de versiones del SQLNCLI, pues tenia instalada la versión 9 (necesaria para un programa de terceros) y la versión 10. He desinstalado ambas versiones y las he vuelto a instalar. Y ya si he conseguido que funcione.

Es cierto que el tema de los espacios en el corte de la sentencia era un error, pues no había espacio entre el final de linea y el siguiente, pero es que anteriormente no llegaba a marcar ni siquiera ese error a nivel sintáctico.

Después de algún tiempo haciendo intentos y de buscar información al respecto estaba ya por buscar soluciones alternativas a este problema, pensando que pudiera tratarse de un BUG del proveedor de datos.

Gracias de nuevo por tu ayuda y tu tiempo.

orodriguezca 27-11-2014 20:25:49

bucanero, Me alegra que se haya solucionado el problema.


La franja horaria es GMT +2. Ahora son las 17:19:45.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi