Página 1 de 1

Como hago para recorrer una tabla???

Publicado: Mié May 24, 2017 2:34 pm
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

Re: Como hago para recorrer una tabla???

Publicado: Mié May 24, 2017 3:53 pm
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.

Re: Como hago para recorrer una tabla???

Publicado: Mié May 24, 2017 6:01 pm
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

Re: Como hago para recorrer una tabla???

Publicado: Mié May 24, 2017 7:15 pm
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.

Re: Como hago para recorrer una tabla???

Publicado: Mié May 24, 2017 7:23 pm
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.

Re: Como hago para recorrer una tabla???

Publicado: Mié May 24, 2017 8:53 pm
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

Re: Como hago para recorrer una tabla???

Publicado: Mié May 24, 2017 10:27 pm
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 ;-)

Re: Como hago para recorrer una tabla???

Publicado: Mié May 24, 2017 11:30 pm
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.

Re: Como hago para recorrer una tabla???

Publicado: Jue May 25, 2017 10:11 am
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

Re: Como hago para recorrer una tabla???

Publicado: Jue May 25, 2017 12:43 pm
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.

Re: Como hago para recorrer una tabla???

Publicado: Jue May 25, 2017 6:45 pm
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.

Re: Como hago para recorrer una tabla???

Publicado: Jue May 25, 2017 9:30 pm
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.

Re: Como hago para recorrer una tabla???

Publicado: Jue May 25, 2017 9:53 pm
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.