Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   SQL (https://www.clubdelphi.com/foros/forumdisplay.php?f=6)
-   -   Recorrer dataset, no funciona bien. (https://www.clubdelphi.com/foros/showthread.php?t=93798)

JorgeDM 08-03-2019 21:45:56

Recorrer dataset, no funciona bien.
 
hace poco tenía un modulo en delphi XE2 con conección a SQL Server 2008 conectados a través de BDE, funcionaba bien, por motivos en los que molestaba la conección con BDE migre a XE8, y la conección
la hice con FireDAC, todo super, el problema es el siguiente, creo con un TFDQuery una consulta que me devuelve 24 registros, estoy recorriendo el query con un for, dentro del ciclo estoy sacando datos
de cada registro y actualizo otra tabla con esos datos, al llegar al registro 24 el intenta realizar el update y se queda pegado el modulo. Los registro del 1 al 23 los actualiza bien pero se queda en el ultimo.
Espero me entiendan y se los agradezco de ante mano, así tengo el fuente

for cont := 1 to Query6.RecordCount do
begin
qconsr := nil;
qconsr := TQuery.create(qconsr);
qconsr.DatabaseName := Md_comun.BASEDATOS.DatabaseName;
madr := '';
madr := 'update pago set deter = ' + FloatToStr(v1) +
' where nrocredito = ' +Query6.FieldByName('nro_credito').AsString + ' and documento = ' + Query6.FieldByName('documento').AsString + ' and consecutivo = ' +
Query6.FieldByName('consecutivo').AsString;
with qconsr do
begin
Close;
SQL.Clear;
SQL.Add(madr);
ExecSQL;
end;
Query6.Next;
end; // Fin For

Casimiro Notevi 08-03-2019 22:05:19

Primero de todo, ¡¡¡bienvenido!!!
Por favor, lee nuestra guía de estilo, gracias.
No olvides usar las etiquetas para código, ejemplo:



También, cuando vayas a preguntar algo, debes crear un hilo nuevo, no escribas cualquier cosa en cualquier hilo.
Solamente debes escribir en otros hilos para contestar a los que han iniciado el mismo.

Seguidamente, en tu código, seguramente debas cambiar:
Código Delphi [-]
for cont := 1 to Query6.RecordCount do
por
Código Delphi [-]
for cont := 0 to Query6.RecordCount -1 do

Aunque lo mejor es:
Código Delphi [-]
while not query.eof do

Además veo cosas raras en tu código, estás mezclando qconsr y query6. Supongo que te has despistado y has hecho un copia/pega mal.
O lo mismo no lo he llegado a entender bien.

ecfisa 08-03-2019 23:55:29

Hola.

Agregando a lo que te aconseja Casimiro, siempre que puedas, usa parámetros para evitar la inyección SQL.

Algo similar a esto:
Código Delphi [-]
var
  qconsr : TQuery;
  cont   : Integer;
begin
  Query6.First;
  while not Query6.Eof do
  begin
    for cont := 0 to Query6.RecordCount -1 do
    begin
      qconsr := TQuery.create(nil);
      try
        qconsr.DatabaseName := Md_comun.BASEDATOS.DatabaseName;
        qconsr.SQL.Clear;
        qconsr.SQL.Add('UPDATE PAGO SET DETER = P1 WHERE NROCREDITO = P2');
        qconsr.SQL.Add('AND DOCUMENTO = P3 AND CONSECUTIVO = P4');
        qconsr.ParamByName('P1').AsFloat  := v1;
        qconsr.ParamByName('P2').AsString := Query6.FieldByName('nro_credito').AsString;
        qconsr.ParamByName('P3').AsString := Query6.FieldByName('documento').AsString;
        qconsr.ParamByName('P4').AsString := Query6.FieldByName('consecutivo').AsString;
        qconsr.ExecSQL;
      finally
        qconsr.Free;
      end;
    end; // Fin For
    Query6.Next;
  end;
end;
Escribí el ejemplo sobre la marcha y no está probado, no des por sentado su correcto funcionamiento.

Saludos :)

JorgeDM 09-03-2019 00:38:27

Casimiro, muchas gracias por cada apunte ya había probado los puntos que me dice pero se sigue pausando allí, este es un ejemplo mas completo

Código Delphi [-]
with Query6 do
  begin
    Query6.Close;
    Query6.Params[0].AsString := Edit_ano.Text;
    Query6.Params[1].AsString := mes;
    Query6.Open;
  end;

v1 := 0;

  for cont := 1 to Query6.RecordCount do
  begin
    v1 := Query6.FieldByName('reversion').AsInteger;
    Table2.Open;
    Table2.Insert;
    Table2.FieldByName('cuenta').Value := '139905';
    Table2.FieldByName('num_mov').Value := '138';
    Table2.FieldByName('tipo_mov').Value := 'DT';
    Table2.FieldByName('consec').Value := cons;
    Table2.FieldByName('ano_mov').Value := Editano.Text;
    Table2.FieldByName('mes_mov').Value := mes;
    Table2.Post;
    Table2.Close;
     qconsr := nil;
    qconsr := TQuery.create(qconsr);
    qconsr.DatabaseName := Md_comun.BD_Tesoreria.DatabaseName;
    madr := '';
        madr := 'update pagos  set deter = ' + FloatToStr(v1) +
      ' where nrocredito = ' +
      Query6.FieldByName('nro_credito').AsString + ' and documento = ' +
      Query6.FieldByName('documento').AsString + ' and consecutivo = ' +
      Query6.FieldByName('consecutivo').AsString;
    with qconsr do
    begin
      Close;
      SQL.Clear;
      SQL.Add(madr);
      ExecSQL;
    end;
    Query6.Next;
  end;

como digo funciona bien hasta llegar al ultimo registro justo en ExecSQL muere, y me bloque al modulo
Código Delphi [-]
with qconsr do
    begin
      Close;
      SQL.Clear;
      SQL.Add(madr);
      ExecSQL;
    end;

JorgeDM 09-03-2019 00:44:50

Ecfisa, muchas gracias lo probaré, me tiene cabezón esa linea :D, no doy ni daré por sentado nada en la vida, en estos momentos solo quiero saber por qué se esta suspendiendo la actualización con SQL

Casimiro Notevi 09-03-2019 10:51:18

Cita:

Empezado por JorgeDM (Mensaje 530975)
... solo quiero saber por qué se esta suspendiendo la actualización con SQL

Ya te lo he contestado.

orodriguezca 09-03-2019 16:26:42

Delphi XE8?, A veces pasan cosas "raras" con el depurador y nos hace creer que la ejecución se ha detenido en una sentencia cuando en realidad se detiene en sentencias posteriores. Sugerencia: Coloca un punto de interrupción en Query6.Next. Esto con el objetivo de verificar si realmente el código se "congela" en ExecSQL.

A Tener en cuenta:

1. La observación de casimiro: al recorrer DataSet de principio a fin lo recomendado es usar
Código Delphi [-]
while not query.eof do
2.
Código Delphi [-]
qconsr := nil
NO libera el objeto qconsr . En tu código está ocurriendo una fuga de memoria cada vez que creas el objeto qconsr porque nunca está siendo liberado. En el código mostrado por ecfisa se ilustra una forma correcta de crear y destruir el objeto qconsr

3. Del código se puede deducir que los componentes utilizados son BDE, por lo que supongo que utilizas tanto BDE como FireDac en la aplicación. Pregunta ¿El código funcionaba bien antes de FireDac o FireDac fue necesario para resolver otro problema?

4. Verifica el siguiente código, no probado, en el que se hace uso del while y de try-finally:
Código Delphi [-]
  Query6.Close;
  Query6.Params[0].AsString := Edit_ano.Text;
  Query6.Params[1].AsString := mes;
  Query6.Open;

  while not Query6.eof do
  begin
      v1 := Query6.FieldByName('reversion').AsInteger;
      Table2.Open;
      Table2.Insert;
      Table2.FieldByName('cuenta').Value := '139905';
      Table2.FieldByName('num_mov').Value := '138';
      Table2.FieldByName('tipo_mov').Value := 'DT';
      Table2.FieldByName('consec').Value := cons;
      Table2.FieldByName('ano_mov').Value := Editano.Text;
      Table2.FieldByName('mes_mov').Value := mes;
      Table2.Post;
      Table2.Close;

      qconsr := TQuery.create(qconsr);
      try
          qconsr.DatabaseName := Md_comun.BD_Tesoreria.DatabaseName;
          madr := 'update pagos  set deter = ' + FloatToStr(v1) +
                  ' where nrocredito = ' + Query6.FieldByName('nro_credito').AsString +
                  ' and documento = ' +   Query6.FieldByName('documento').AsString +
                  ' and consecutivo = ' + Query6.FieldByName('consecutivo').AsString;
          qconsr.SQL.Text := madr;
          qconsr.ExecSQL;
      finally
          qconsr.free;
      end;
      Query6.Next;
  end;

5. En un enfoque completamente alternativo, y aprovechando el poder de las bases de datos, prueba a utilizar la sentencia SQL MERGE, la cual te permite actualizar/modificar/borrar masivamente registros de una tabla a partir de otra tabla o de una subconsulta.

WHILENOTEOF 09-03-2019 20:00:55

Como se ha comentado, para recorrer el dataset es mejor con :

Código Delphi [-]
Dataset.First;
while not DataSet.Eof do
 begin
  //código
  DataSet.Next;
 end;

El poner
Código Delphi [-]
for cont := 1 to Query6.RecordCount do
o poner
Código Delphi [-]
for cont := 0 to Query6.RecordCount -1 do
, no te va a cambiar nada ya que la variable cont no la estás utilizando para nada.

Casimiro Notevi 10-03-2019 10:46:39

Cita:

Empezado por WHILENOTEOF (Mensaje 530979)
El poner Código Delphi [-]for cont := 1 to Query6.RecordCount do
o poner Código Delphi [-]for cont := 0 to Query6.RecordCount -1 do

, no te va a cambiar nada ya que la variable cont no la estás utilizando para nada.

Precisamente, aparte de todos los problemas que ya se han comentado por los compañeros que han respondido, ese bucle está claramente mal y es inservible.
Si hay 5 registros, el (0,1,2,3,4), al hacer ese bucle se están tratando los datos del 1 al 4, y el 0 (cero) se pierde y el 5 no leerá nada tampoco, pues no existe.

WHILENOTEOF 10-03-2019 12:53:37

Cita:

Empezado por Casimiro Notevi (Mensaje 530986)
Precisamente, aparte de todos los problemas que ya se han comentado por los compañeros que han respondido, ese bucle está claramente mal y es inservible.
Si hay 5 registros, el (0,1,2,3,4), al hacer ese bucle se están tratando los datos del 1 al 4, y el 0 (cero) se pierde y el 5 no leerá nada tampoco, pues no existe.


Entiendo que no es la forma habitual-correcta de hacerlo, pero los dos bucles hacen su trabajo bien, que es recorrer un dataset de 5 registros, el que la variable count vaya del 0 al 4, o del 1 al 5, es indiferente para este caso.

Casimiro Notevi 10-03-2019 13:42:53

Cita:

Empezado por WHILENOTEOF (Mensaje 530987)
Entiendo que no es la forma habitual-correcta de hacerlo, pero los dos bucles hacen su trabajo bien, que es recorrer un dataset de 5 registros, el que la variable count vaya del 0 al 4, o del 1 al 5, es indiferente para este caso.

Depende de los componentes y de la base de datos. Algunos tratan el primer registro como 0 (cero) y hay que decirle esplícitamente que posicione en el registro 0, en caso contrario ese registro se lo saltaría.
Ignoro el caso este de los componentes que esté usando y la base de datos.

WHILENOTEOF 10-03-2019 19:13:28

Cita:

Empezado por Casimiro Notevi (Mensaje 530989)
Depende de los componentes y de la base de datos. Algunos tratan el primer registro como 0 (cero) y hay que decirle esplícitamente que posicione en el registro 0, en caso contrario ese registro se lo saltaría.
Ignoro el caso este de los componentes que esté usando y la base de datos.

Casimiro, creo que estamos hablando de dos cosas distintas, el que al ejecutar la query nos situemos en el primer registro, suele ser el comportamiento habitual, en todo caso si no lo sabemos nos situaríamos con Query.First , como la variable del bucle no la utilizamos dentro del mismo, da igual que empiece por 0 y termine en 4 (hará 5 iteraciones) , o que empiece en 1 y termine en 5 (serán las mismas 5 iteraciones), o que empiece en 10000 y acabe en 10004 (serán las mismas 5 iteraciones).

Casimiro Notevi 10-03-2019 20:47:45

Sí, te entiendo, pero aunque te parezca raro, porque a mí me lo parece, me he encontrado con componentes que acceden a bases de datos a los que hay que decirle que se posicione en la posición determinada, ejemplo:
Código:

query.open
for i=0 to query.recordcount -1
  query.position = i
  ...
  ...
  query.next

En este caso, si fuese for i=1 to .... no posicionaría nunca en el primer registro, el cero.

Caminante 11-03-2019 16:28:15

Hola


Solo agregar que no siempre recordcount devuelve un valor valido. Eso dependiendo del tipo de componente y base de datos usada.


Saludos

JorgeDM 11-03-2019 16:36:08

se bloquea la ejecución de un Query
 
Buenos días, ya había mandado esta inquietud en un hilo que no hice, y parece ser que lo quitarón :D, migre de XE2 donde utilizaba BDE, pase el modulo a delphi XE8 y cambie a FireDAC, estoy haciendo pruebas, el recorre el ciclo bien hasta el ultimo registro, cuando va a terminar el ciclo el ultimo registro se queda en
Código Delphi [-]
ExecSQL
del qrconsr, ya le hice unos cambios que me habían comentado en el anterior Hilo donde copie la inquietud pero sigue el error,
pero sigue pegándose en el ultimo registro. envió el código

Código Delphi [-]
 with Query6 do
  begin
    Query6.Close;
    Query6.Params[0].AsString := Edit_ano.Text;
    Query6.Params[1].AsString := mes;
    Query6.Open;
  end;

v1 := 0;

  while not Query6.Eof do
  begin
    v1 := Query6.FieldByName('reversion').AsInteger;
    Table2.Open;
    Table2.Insert;
    Table2.FieldByName('cuenta').Value := '139905';
    Table2.FieldByName('num_mov').Value := '138';
    Table2.FieldByName('tipo_mov').Value := 'DT';
    Table2.FieldByName('consec').Value := cons;
    Table2.FieldByName('ano_mov').Value := Edit_ano.Text;
    Table2.FieldByName('mes_mov').Value := mes;
    Table2.Post;
    Table2.Close;
     
qconsr := TFDQuery.create(nil);

    try
      qconsr.ConnectionName := Md_comun.BD_Tesoreria.ConnectionName;
      qconsr.SQL.Clear;
      qconsr.SQL.Add('UPDATE pago set deter = :P1 ');
      qconsr.SQL.Add('WHERE nrocredito = :P2 AND documento = :P3 ');
      qconsr.SQL.Add('AND consecutivo = :P4');
      qconsr.ParamByName('P1').AsFloat  := v1;
      qconsr.ParamByName('P2').AsString := Query6.FieldByName('nrocredito').AsString;
      qconsr.ParamByName('P3').AsString := Query6.FieldByName('documento').AsString;
      qconsr.ParamByName('P4').AsString := Query6.FieldByName('consecutivo').AsString;
      qconsr.ExecSQL;
    finally
      qconsr.Free;
    end;

    Query6.Next;
  end;

oscarac 11-03-2019 16:44:37

intenta colocar un
query6.first antes que empiece a recorrer

prueba con eso

JorgeDM 11-03-2019 17:29:58

un saludo
 
hola [oscarac], ya lo tengo así lo, recorrí las lineas después del while y se queda en ExecSQL, no salta a tirar un error, me dirijo al sqlserver y reviso el monitor de actividades y aparece el Update en
estado suspendido, apenas termino el programa se libera en SQLserver, también copie la cadena del Query6 cuando estoy en el ultimo registro a SQLServer y me funciona bien. Me tiene pensativo ese
fragmento de código, cuando lo tenía en XE2 funcionaba bien, pero ahora queda en ese registro. Seguiré mirando y probando, muchas gracias por el aporte.

oscarac 11-03-2019 17:36:31

pregunta importante:
te has fijado que exista el registro que quieres actualizar?

JorgeDM 11-03-2019 17:40:13

buenos días
 
a todos muchas gracias por sus aportes, les entiendo muy bien cada punto que me han colocado y otros puntos que no sabía me han ayudado mucho en conocimiento, bueno pasando más importante
por ahora, he hecho los cambios ya que me han propuesto, pero sigue en lo mismo, hace muy bien el recorrido hasta el ultimo registro, recorro cada linea y al llegar al execSQL, no pasa de ahí, voy al
SQL Server y veo en el monitor de actividades que estoy en Update Suspendido, me toca matar el proceso, o cerrar el programa para que se libere.
Envío el código como lo tengo en estos momentos, seguiré haciendo pruebas

Código Delphi [-]
  with Query6 do
  begin
    Query6.Close;
    Query6.Params[0].AsString := Edit_ano.Text;
    Query6.Params[1].AsString := mes;
    Query6.Open;
  end;

v1 := 0;

Query6.First;
  while not Query6.Eof do
  begin
    v1 := Query6.FieldByName('reversion').AsInteger;
    Table2.Open;
    Table2.Insert;
    Table2.FieldByName('cuenta').Value := '139905';
    Table2.FieldByName('num_mov').Value := '138';
    Table2.FieldByName('tipo_mov').Value := 'DT';
    Table2.FieldByName('consec').Value := cons;
    Table2.FieldByName('ano_mov').Value := Edit_ano.Text;
    Table2.FieldByName('mes_mov').Value := mes;
    Table2.Post;
    Table2.Close;
     
qconsr := TFDQuery.create(nil);

    try
      qconsr.ConnectionName := Md_comun.BD_Tesoreria.ConnectionName;
      qconsr.SQL.Clear;
      qconsr.SQL.Add('UPDATE pago set deter = :P1 ');
      qconsr.SQL.Add('WHERE nrocredito = :P2 AND documento = :P3 ');
      qconsr.SQL.Add('AND consecutivo = :P4');
      qconsr.ParamByName('P1').AsFloat  := v1;
      qconsr.ParamByName('P2').AsString := Query6.FieldByName('nrocredito').AsString;
      qconsr.ParamByName('P3').AsString := Query6.FieldByName('documento').AsString;
      qconsr.ParamByName('P4').AsString := Query6.FieldByName('consecutivo').AsString;
      qconsr.ExecSQL;
    finally
      qconsr.Free;
    end;

    Query6.Next;
  end;

haciendo las pruebas, copio la cadena del update del qconsr en el ultimo registro, y la pruebo directamente en SQLServer y me funciona sin problema.

JorgeDM 11-03-2019 20:20:54

bloque modulo delphi XE8 por Query
 
[oscarac] si ya verifique, en el momento que estoy recorriendo las lineas del procedimiento, en el update copio toda la cadena y la pego en SQL Server y me funciona normal, pero en delphi queda suspendida en el query.


La franja horaria es GMT +2. Ahora son las 17:39:44.

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