In order for this site to work correctly we need to store a small file (called a cookie) on your computer. Most every site in the world does this, however since the 25th of May 2011, by law we have to get your permission first. Please abandon the forum if you disagree.

Para que este foro funcione correctamente es necesario guardar un pequeño fichero (llamado cookie) en su ordenador. La mayoría de los sitios de Internet lo hacen, no obstante desde el 25 de Marzo de 2011 y por ley, necesitamos de su permiso con antelación. Abandone este foro si no está conforme.

Como hago para recorrer una tabla???

SQL databases
Responder
Avatar de Usuario
XeviCOMAS
Mensajes: 582
Registrado: Sab Mar 12, 2011 8:16 pm

Como hago para recorrer una tabla???

Mensaje por XeviCOMAS »

Pues eso... ¿Como hago para recorrer una tabla para cambiar valores de campos???

Lo que haria en DBase...

N := 0
While MIDBF->( !Eof() )
If MIDBF->MICAMPO = N
MIDBF->MICAMPO := N+1
Else
N++
loop
EndIf
MIDBF->( DbSkip() )
EndDo

Gracias.

Un Saludo,
Xevi
Un Saludo,
Xevi.
Avatar de Usuario
XeviCOMAS
Mensajes: 582
Registrado: Sab Mar 12, 2011 8:16 pm

Re: Como hago para recorrer una tabla???

Mensaje por XeviCOMAS »

Liado con eso...
Por ejemplo, lo necesito para "renumerar" los asientos de una contabilidad, Cargo todo el diario en un array
aItems := :QueryArray( "SELECT assent,id FROM assentaments ORDER BY dataa,assent" )
recorro el array y renumero los numeros de asiento, hasta hay, bien, PERO

Cuando se trata de actualizar la tabla, registro a registro
:Execute( "UPDATE assentaments SET assent = " +Str(nAssent)+ " WHERE id = " + Str(aItems[n,2]) )
Si son pocos registros, nada, pero cuando afecta al principio de la tabla y hay que renumerar los 20.000 registros siguientes, se puede demorar 1 hora, si hay que hacer 20.000 UPDATEs.

No hay alguna forma más "ligera" de hacer UPDATE a un conjunto de registros, que no cumplen la misma condicion WHERE. ???


Gracias.

Un Saludo,
Xevi.
Un Saludo,
Xevi.
hgarciaj
Mensajes: 107
Registrado: Jue Sep 23, 2010 12:44 am

Re: Como hago para recorrer una tabla???

Mensaje por hgarciaj »

yo los borraba y los volvía a grabar es mucho más rápido un insert que un update y te recomiendo que generes un archivo csv y veas la sintaxis del insert from, o bien revisa la sintaxis del insert con la cláusula on duplicate key
Saludos
Héctor García
Claudio C
Mensajes: 60
Registrado: Dom Sep 20, 2015 8:13 pm
Ubicación: Buenos Aires

Re: Como hago para recorrer una tabla???

Mensaje por Claudio C »

Hola compañero:

El problema es que estas tratando una tabla SQL 'registro a registro' .

Te recomiendo inviertas tiempo en ver el tema de Stored Procedures de MariaDB/MySQL ( esto te permite generar procesos mas complejos y resolverlos en el server )

Tuve el mismo problema y lo resolvi 'del lado del servidor' en dos pasadas usando un auxiliar y aprovechando el campo autoincremental del auxiliar ...
Te paso un fragmento que te puede ayudar:

CREATE TEMPORARY TABLE auxRenu LIKE asientosrenumerar_temporal ; -- Crea auxiliar copiando de temporal
START TRANSACTION ;
-- Carga un auxiliar para ordenarlo y obtener la numeración del campo autoincremental nuAsiento
INSERT INTO auxRenu ( orden , feAsiento , idAsiento )
SELECT asientosencabezado.orden , asientosencabezado.feAsiento , asientosencabezado.idAsiento
FROM asientosencabezado
ORDER BY asientosencabezado.feAsiento , asientosencabezado.orden ;
-- Actualiza encabezado con auxiliar
UPDATE asientosencabezado
INNER JOIN auxRenu ON asientosencabezado.idAsiento = auxRenu.idAsiento
SET asientosencabezado.nuAsiento = auxRenu.nuAsiento ;
COMMIT ; -- Confirma transaccion
DROP TEMPORARY TABLE IF EXISTS auxRenu ; -- Borra auxiliar si existe

No es lo mas elegante, lo se, pero funciona.
Se que existen otras formas de reemplazar el numero de asiento usando variables ( siempre en el servidor ) para reemplazar el campo tipo: @nNuAsiento:= @nNuAsiento + 1 ... pero en mi caso no era viable.

El codigo lo puse en un SP de maria DB y 'vuela'...

Un saludo,
Claudio.
Avatar de Usuario
XeviCOMAS
Mensajes: 582
Registrado: Sab Mar 12, 2011 8:16 pm

Re: Como hago para recorrer una tabla???

Mensaje por XeviCOMAS »

Gracias, Hector y Claudio.

Pero... seguiré buscando alternativa a borrar/recrear tabla entera, por modificar un campo de parte o todos los registros.

De momento, leyendo y buscando, hechando mano de CASE...

for...
cSQL += " WHEN id >=" +Str(nId1)+ " AND id <=" +Str(nId2)+ " THEN " +Str(nAssent)
next
"UPDATE assentaments SET assent = CASE" +cSQL+ " ELSE assent END"

Me casi sirve, pues si actualizo un campo de una tabla de 20.000 registros, no llega al minuto en hacerlo... nada comparable con DBFs, que en segundos lo hace... pero, como me he empeñado en cambiar a las BBDD MariaDB... alguna pega más que he encontrado, no me desanima, de momento.

Un Saludo,
Xevi.
Un Saludo,
Xevi.
hgarciaj
Mensajes: 107
Registrado: Jue Sep 23, 2010 12:44 am

Re: Como hago para recorrer una tabla???

Mensaje por hgarciaj »

Xevi:

Solo te recomiendo como Claudio dice no insistas en modificar registro a registro porque cada vez que lo haces es una llamada al servidor, si contruyes la instrucción sql a manera de que mandes todas las modificaciones en un variable o construyas una tabla temporal como dice Claudio entonce en lugar de hacer 20mil llamadas al servidor harás una. Cambia la forma de pensar, en tablas dbf la actualización es por registro, en maria DB MySQL es por transacción, bloque de registros, batch de actualizaciones o como quieras llamarle
Saludos
Héctor García
Avatar de Usuario
jfgimenez
Site Admin
Mensajes: 5706
Registrado: Lun Abr 06, 2015 8:48 pm
Contactar:

Re: Como hago para recorrer una tabla???

Mensaje por jfgimenez »

Xevi,

si lo que quieres es simplemente renumerar, lo más sencillo es algo así (escrito al vuelo):

Código: Seleccionar todo

SET @n:=0;
UPDATE MiTabla SET MiCampo=(@n:=@n+1) ORDER BY <el_orden_que_necesites>
Pruébalo y dime si va rápido ;-)
José F. Giménez
[Equipo de Xailer / Xailer team]
http://www.xailer.com
http://www.xailer.info
Avatar de Usuario
XeviCOMAS
Mensajes: 582
Registrado: Sab Mar 12, 2011 8:16 pm

Re: Como hago para recorrer una tabla???

Mensaje por XeviCOMAS »

José

Lo que comentas seria para "enumerar" registros correlativos... TODOS y cada uno distinto incrementado de 1... no me sirve.

el problema no es SOLO enumerar... sinó renumerar.
una tabla de asientos/apuntes contables... igual hay un registro o igual hay 50 que se corresponden a un mismo numero de asiento.
Así pues
el registro 1 num asiento 1
del registro 2 al 5 num asiento 8
del registro 6 al 7 num asiento 9
el registro 8 num asiento 12
del registro 9 al 20 num asiento 10
...

Así pues, al renumerar, deberia de quedar...
el registro 1 num asiento 1
del registro 2 al 5 num asiento 2
del registro 6 al 7 num asiento 3
el registro 8 num asiento 4
del registro 9 al 20 num asiento 5
...

De ahí que como lo hago, es leer que id tienen cada registro, y tirando de CASE les pongo el num asiento correcto.

este es mi código...

WITH OBJECT xSource() //Una funcion que tengo encargada de crear el objeto conexion MariaDB
aItems := :QueryArray( "SELECT assent,id FROM assentaments ORDER BY dataa,assent" )
If Len(aItems) > 0
nAssent := 1
nId1 := aItems[1,2]
nId2 := aItems[1,2]
nAnterior := aItems[1,1]
o:oProgressBar1:nMax := Len(aItems)
For n:=1 TO Len(aItems)
o:oProgressBar1:nValue := n
ProcessMessages()
If n=1 .or. aItems[n,1] = nAnterior
Else
If nAnterior # nAssent
cSQL += " WHEN id >=" +AllTrim(Str(nId1))+ " AND id <=" +AllTrim(Str(nId2))+ " THEN " +AllTrim(Str(nAssent))
EndIf
nAssent++
nAnterior := aItems[n,1]
nId1 := aItems[n,2]
EndIf
nId2 := aItems[n,2]
Next

If Len(aItems) > 0 .and. nAnterior # nAssent
cSQL += " WHEN id >=" +AllTrim(Str(nId1))+ " AND id <=" +AllTrim(Str(nId2))+ " THEN " +AllTrim(Str(nAssent))
EndIf

If !Empty(cSQL)
o:oProgressBar1:lVisible := .F.
o:oLabel1:cText := IF( AppData:nIdioma = 1, "Espereu..." +Chr(10)+ "Actualitzant Base de Dades!!!", "Espere..." +Chr(10)+ "Actualizando Base de Datos!!!" )
ProcessMessages()
:Execute( "UPDATE assentaments SET assent = CASE" +cSQL+ " ELSE assent END" )
EndIf
EndIf
END

PERO... cuando hay muchos WHEN...THEN...WHEN...THEN... (alrededor de 5 o 6.000) sigue siendo lento y pesado (1min), en comparación a DBFs (5 o 10seg).

Gracias.

Un Saludo,
Xevi.
Un Saludo,
Xevi.
Avatar de Usuario
XeviCOMAS
Mensajes: 582
Registrado: Sab Mar 12, 2011 8:16 pm

Re: Como hago para recorrer una tabla???

Mensaje por XeviCOMAS »

José,

siguiendo tu hilo...
SET @n:=0;
UPDATE MiTabla SET MiCampo=(@n:=@n+1) ORDER BY <el_orden_que_necesites>

No hay alguna forma de hacer, no se...
SET @miarray:={ {1,1}, {2,2}, {3,2}, {4,2}, {5,2}, {6,3}, {7,3}, {8,4} }...
UPDATE MiTabla SET MiCampo = CASE WHEN SI( BUSCA( @miarray, elemento1 = id ) ) THEN elemento2 ELSE MiCampo


O

SET @miarray:={ {1,1,1}, {2,5,2}, {6,7,3}, {8,8,4}, {9,20,5} }
UPDATE MiTabla SET MiCampo = CASE WHEN SI( BUSCA( @miarray, elemento1 >= id ) AND BUSCA( @miarray, elemento2 <= id ) ) THEN elemento3 ELSE MiCampo


Con un WHEN...THEN habia suficiente, NO ???


Un Saludo,
Sevi
Un Saludo,
Xevi.
Avatar de Usuario
XeviCOMAS
Mensajes: 582
Registrado: Sab Mar 12, 2011 8:16 pm

Re: Como hago para recorrer una tabla???

Mensaje por XeviCOMAS »

Bien, aprendiendo y peleándome con MariaDB i SQL, sigo.

He hallado una "manera" que creo que me ayudará a que UPDATE no sea tan pesado, creo.

En Heidi me funciona, ahora bien, con Xailer NO
SET @c:='{17072, 06656}, {17073, 06656}, {17074, 06656}, {17075, 06656}';
SET @n1:=0;
UPDATE assentaments SET assent= CASE WHEN (@n1:=INSTR( @c, CONCAT('{',RTRIM(id),',') )) > 0 THEN SUBSTR(@c,@n1+8,5) ELSE id END;

Lo dicho, con Heidi rula bien
Con Xailer...
:Execute( "SET @c:='{17072, 06656}, {17073, 06656}, {17074, 06656}, {17075, 06656}';SET @n1:=0;UPDATE assentaments SET assent= CASE WHEN (@n1:=INSTR( @c, CONCAT('{',RTRIM(id),',') )) > 0 THEN SUBSTR(@c,@n1+8,5) ELSE id END;" )

Me lanza el error que anexo :cry:

QUE HAGO MAL???
Alguna solución o aporte???
Gracias.

Un Saludo,
Xevi.
Adjuntos
Captura.JPG
Captura.JPG (47.23 KiB) Visto 55921 veces
Un Saludo,
Xevi.
Avatar de Usuario
XeviCOMAS
Mensajes: 582
Registrado: Sab Mar 12, 2011 8:16 pm

Re: Como hago para recorrer una tabla???

Mensaje por XeviCOMAS »

Visto!!!

debo de hacer dos llamadas Execute

Y... Ya tengo solucionado la "renumeración" (he conseguido bajar de 63seg a 12seg :shock: :P
Me doy por satisfecho!!!

Así es como lo hago, por si a alguien le puede servir (y no perder 3 dias, como yo, pero que saben a gloria al conseguirlo) :mrgreen:

:Execute( "SET @n1:=0, @c:='" +cSQL+ "';" )
:Execute( "UPDATE assentaments SET assent= CASE WHEN (@n1:=INSTR( @c, CONCAT('{',LPAD(RTRIM(id),5,'0'),',') )) > 0 THEN SUBSTR(@c,@n1+8,5) ELSE assent END;" )

donde cSQL lo voy montando segun criterio de si hay que cambiar la numeración del registro.
por ej, podria ser...
'{17074, 00004}, {17075, 00004}, {00010, 00005}, {00011, 00006}, {00012, 00007}, {00015, 00007}, {00019, 00007}, {00018, 00007}, {00017, 00007}, {00016, 00007}, {00013, 00007}, {00014, 00007}, {00021, 00008}, {00022, 00008}, {00020, 00008}, {00023, 00009}, {00025, 00009}, {00026, 00009}, {00027, 00009}, {00024, 00009}'

Gracias.

Very Happy!!!

Un Saludo,
Xevi.
Un Saludo,
Xevi.
Avatar de Usuario
jfgimenez
Site Admin
Mensajes: 5706
Registrado: Lun Abr 06, 2015 8:48 pm
Contactar:

Re: Como hago para recorrer una tabla???

Mensaje por jfgimenez »

XeviCOMAS escribió: el problema no es SOLO enumerar... sinó renumerar.
una tabla de asientos/apuntes contables... igual hay un registro o igual hay 50 que se corresponden a un mismo numero de asiento.
Así pues
el registro 1 num asiento 1
del registro 2 al 5 num asiento 8
del registro 6 al 7 num asiento 9
el registro 8 num asiento 12
del registro 9 al 20 num asiento 10
...

Así pues, al renumerar, deberia de quedar...
el registro 1 num asiento 1
del registro 2 al 5 num asiento 2
del registro 6 al 7 num asiento 3
el registro 8 num asiento 4
del registro 9 al 20 num asiento 5
...
Se pueden hacer operaciones dentro de la sentencia. No todo lo que se quiera, pero sí mucho, incluso usando pequeños trucos. Prueba esto:

Código: Seleccionar todo

SET @a=0,@n:=0;
UPDATE diario SET asiento=CASE WHEN @a=asiento THEN @n ELSE (@n:=@n+1+(@a:=asiento)-@a) END
ORDER BY asiento,registro
Esto funcionaría perfectamente para el caso que indicas arriba.
José F. Giménez
[Equipo de Xailer / Xailer team]
http://www.xailer.com
http://www.xailer.info
Avatar de Usuario
XeviCOMAS
Mensajes: 582
Registrado: Sab Mar 12, 2011 8:16 pm

Re: Como hago para recorrer una tabla???

Mensaje por XeviCOMAS »

José,

muchas gracias por tu tiempo i tu ayuda.
IMPRESIONANTE!!!
Esta última solución que me has aportado, funciona de primera, sin apenas código, y... VUELA!!!
0,33seg

lo que en DBFs tarda 7 o 9 seg. y apurando con mi código para SQL de 60 o 70seg habia llegado a 12 o 13seg.
Estoy que no me lo creo... lo pondré a probar, probar, probar.

Muchas gracias!!!

Un Saludo,
Xevi.
Un Saludo,
Xevi.
Responder