Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Firebird e Interbase (https://www.clubdelphi.com/foros/forumdisplay.php?f=19)
-   -   ¿Cómo copiar todos los registros de una tabla a otra? (https://www.clubdelphi.com/foros/showthread.php?t=77546)

Casimiro Notevi 06-02-2012 17:55:15

¿Cómo copiar todos los registros de una tabla a otra?
 
Hola, explico lo que quiero hacer:

Código:

tabla-A
 campo1
 campo2
 campo3
 campo4
 campo5

tabla-B
 campo1
 campo2
 campo3
 campo4
 campo5

Ambas tablas son iguales, para pasar todos los registros de una a otra se puede hacer algo como esto:
Código SQL [-]
insert into tabla-B  select * from tabla-A

Ahora bien, le ponemos un campo más a tabla-B y queda así:

Código:

tabla-B
 campo0
 campo1
 campo2
 campo3
 campo4
 campo5

¿Cómo se podría hacer?, en SQL, ya que la sentencia va en un store procedure. Ni idea.

Uso Firebird 2.1

Edito:
Tampoco quisiera hacer un for select porque tendría que declarar todos los campos, y sería un inconveniente cada vez que se modificara la tabla, habría que modificar también el store procedure.

Caral 06-02-2012 19:25:50

Hola
Una pregunta amigo:
Siempre va a modificarse una de las tablas ?, me refiero a los campos.
Saludos

Caro 06-02-2012 19:58:37

Hola Casimiro, cuando los campos son diferentes en las tablas, tienes que poner los que campos que coinciden con la tabla del Select, en tu ejemplo no entraría el Campo0 de tu tabla B.

Código SQL [-]

Insert Into tabla-B (campo1, campo2, campo3, campo4, campo5)  select * from tabla-A

Saluditos

newtron 06-02-2012 20:21:03

Anda, eso me lo apunto yo también.

Gracias. :D

Casimiro Notevi 07-02-2012 01:18:21

Cita:

Empezado por Caral (Mensaje 424353)
Hola
Una pregunta amigo:
Siempre va a modificarse una de las tablas ?, me refiero a los campos.
Saludos

Hola, Caral, en principio las tablas son siempre iguales, salvo que en una de ellas hay un campo más, pero siempre será esa la diferencia. Puede ser, casi seguro, que dentro de poco tiempo haya que añadir algún campo más o varios, pero siempre serán iguales todos menos uno de ellos en la tabla B.


Cita:

Empezado por Caro (Mensaje 424355)
Hola Casimiro, cuando los campos son diferentes en las tablas, tienes que poner los que campos que coinciden con la tabla del Select, en tu ejemplo no entraría el Campo0 de tu tabla B.
Saluditos

Hola Caro, muy buena tu idea, aunque lo que no quiero es precisamente eso, tener que declarar los campos, porque irán ampliándose con el tiempo y habría que acordarse de modificar el store procedure.
Lo ideal sería poder recorrer los campos, al igual que se puede hacer desde delphi.
Pero bueno, tu idea es bastante cercana a lo que necesito, será lo que use si no se "nos" ocurre otra cosa :)

Caral 07-02-2012 01:47:23

Hola
En principio no se si se tendrá claro o no que la BD1 contiene los mismos campos que la BD2.
Me imagino que lo que pretendes es que ese dato NO sea relevante, osea, que no importe si los campos son los mismos o no ya que el store procedure pretendes que siempre sea el mismo.
CREO, que la mejor manera seria primero hacer una comprobación de los campos, de las dos BD, esto se puede hacer mas o menos asi:

Código SQL [-]
SELECT RDB$FIELD_NAME
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='BD1' AND RDB$RELATION_NAME='BD2';

Esto te mostrara los campos de cada tabla; Haciendo una comparación de los campos podrás crear tu sentencia, especificando el campo o los campos faltantes por medio de variables.

Por cierto, para saber mas datos de las tablas:

Código SQL [-]
SELECT RDB$FIELD_NAME AS field_name,
RDB$FIELD_POSITION AS field_position,
RDB$DESCRIPTION AS field_description,
RDB$DEFAULT_VALUE AS field_default_value,
RDB$NULL_FLAG AS field_not_null_constraint
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='BD1';

Ya sabes, de esto no se, pero trato de aportarle algo a mi Maestro.;)
Saludos

Casimiro Notevi 07-02-2012 01:58:46

¿Quién diría que eres un novato? ;)
Ambas tablas siempre se diferenciarán en un campo. Si una se modifica, entonces la otra también.

Código:

tabla-A
 campo1
 campo2
 campo3
 campo4
 campo5
 campo6
 campo7
 campo8
 ...
 campoXXX

tabla-B
 campo0  <- único campo distinto
 campo1
 campo2
 campo3
 campo4
 campo5
 campo6
 campo7
 campo8
 ...
 campoXXX


Caral 07-02-2012 02:04:49

Hola
Sigo desubicado, para variar.
Pregunto:
1- Son siempre iguales, salvo por un campo ?
2- Los campos van creciendo, osea, van aumentando en su numero. ?.
Lo digo por que en principio pusiste 4 campos en la primera tabla y cinco en la segunda y hora pones mas.
Ya sabes que poco ayudare, pero si pregunto tal vez a alguien se le encienda la bombilla.:D
Saludos

Casimiro Notevi 07-02-2012 02:19:56

Bueno, me explico mejor, lo anterior era solamente un ejemplo, son dos tablas iguales salvo por un campo. Seguramente se ampliarán con el tiempo con el añadido de más campos porque se necesite hacer algo más.
En principio deben ser iguales salvo ese primer campo. O sea, 'casi' iguales :)
Ahora mismo tiene 29 campos. Y lo que quiero conseguir es "olvidarme" de la misma el día que sea necesario añadir algún nuevo campo para controlar cualquier otra cosa, o sea, que dentro de unos meses, cuando ya te has olvidado de todo, no tenga que decir: "no se sabe por qué falla el programa", y después de mucho perder el tiempo: "el problema era que había que añadir el nuevo campo en un store procedure, y se nos había olvidado."
Resumiendo, da igual los campos que tenga la tabla, lo que se intenta es no tener que controlarlo, que sea un proceso automático. Al igual que en delphi se puede hacer algo así como (de memoria):
Código Delphi [-]
tabla1.open;
while not tabla1.eof do
begin
  tabla2.append;
  for iX=0 to tabla1.fields.count-1 do
    tabla2.fields[iX].value := tabla1.fields[iX].value;
  tabla2.post;
  tabla1.next;
end;

Casimiro Notevi 07-02-2012 02:22:30

Bueno, me voy a dormir, mañana sigo.

¡¡¡GRACIAS!!! :)

Caral 07-02-2012 02:32:53

Hola
Por eso pensé en que si se puede saber que campos tiene cada tabla y guardar los nombres en donde sea se puede usar la consulta que hizo caro, seria algo asi:
Reviso los campos de cada tabla:
Código SQL [-]
SELECT RDB$FIELD_NAME
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='BD1' AND RDB$RELATION_NAME='BD2';
Guardo los datos que como serán nombres de campos podrán ser string e inserto con los datos obtenidos usando la consulta de Caro:
BD1/campos= dato1, dato2, dato3, dato4, dato5
BD2/campos= dato0, dato1, dato2, dato3, dato4, dato5

Código SQL [-]
Insert Into BD2 (dato0, dato1, dato2, dato3, dato4, dato5)  select dato1, dato2, dato3, dato4, dato5 from BD1
Me da la impresión de que la inserción de datos es mas fiable si se ponen los nombres de los campos.
No se amigo, es solo una opinión sin mucha base; Bueno, sin base alguna.:D
Saludos

Caral 07-02-2012 02:34:54

Hola
Vale amigo, mañana lo harás sin problemas, la almohada es la mejor consejera.
Buenas Noches.
Saludos

Neftali [Germán.Estévez] 07-02-2012 11:59:00

Si la tabla no tiene muchos datos, tal vez te saldría a cuenta, dentro del Stored Procedure, añadir el campo0 a la primera tabla, luego hacer el INSERT INTO y finalmente volver a borrar el campo de la primera tabla.

La ventaja que le veo es que cuando añadas más campos, el SP no deberá cambiar.
La desventaja es que si la tabla es muy grande (con muchos datos), habrá que ver el tiempo que tarda en crear y borrar el campo.

fjcg02 07-02-2012 12:13:37

Me da la sensación de que Caral es el que más cerca anda de la solución.

yo haría lo mismo que él, leería los campos de la tabla 1, y montaría la query en una variable de tipo string.

Luego ejecutaría "EXCECUTE STATEMENT CONSULTA" siendo consulta la query que he montado.

No lo he probado. Si funciona, no deberás cambiar nunca el store procedure.

Saludos

Casimiro Notevi 07-02-2012 13:06:46

Hola, gracias por las respuestas.
Neftalí, la tabla tiene bastantes registros porque se tratan precisamente de históricos, la tabla-B es un histórico acumulado de todo lo que hay en tabla-A, así que como todos los históricos, cada vez será más y más grande.
Aunque el método que has indicado es una muy buena idea, muy simple y efectiva.
El método indicado por Caral de obtener los campos desde las tablas del sistema, luego crear la sentencia sql dinámicamente, como también ha indicado fjcg02, es muy factible, y también funciona, seguro.
Lo que voy a hacer es probar ambas formas, me quedaré con la que sea más rápida de ejecución. Y si son muy similares... lo echaré a cara o cruz :)

Gracias de nuevo, ambas soluciones son estupendas y es justo lo que estaba buscando.

roman 07-02-2012 18:31:56

Bueno, pero, ¿qué valor debe ir en ese campo extra? Supongamos que es un campo entero y cero su valor por defecto. No me van a decir que en Firebird no puede hacerse esto:

Código SQL [-]
insert into tabla_b
select 0,* from tabla_a

// Saludos

Caral 07-02-2012 18:41:34

Hola
Muy interesante.
Pregunto:
Que campo de la tabla tomara para ese dato ?, el 1, 2, 3 etc..??.
Saludos

guillotmarc 07-02-2012 18:50:28

Hola Casimiro.

Cita:

Empezado por Casimiro Notevi (Mensaje 424374)
Bueno, me explico mejor, lo anterior era solamente un ejemplo, son dos tablas iguales salvo por un campo. Seguramente se ampliarán con el tiempo con el añadido de más campos porque se necesite hacer algo más.
En principio deben ser iguales salvo ese primer campo. O sea, 'casi' iguales :)
Ahora mismo tiene 29 campos. Y lo que quiero conseguir es "olvidarme" de la misma el día que sea necesario añadir algún nuevo campo para controlar cualquier otra cosa, o sea, que dentro de unos meses, cuando ya te has olvidado de todo, no tenga que decir: "no se sabe por qué falla el programa", y después de mucho perder el tiempo: "el problema era que había que añadir el nuevo campo en un store procedure, y se nos había olvidado."
Resumiendo, da igual los campos que tenga la tabla, lo que se intenta es no tener que controlarlo, que sea un proceso automático. Al igual que en delphi se puede hacer algo así como (de memoria):
Código Delphi [-]tabla1.open; while not tabla1.eof do begin tabla2.append; for iX=0 to tabla1.fields.count-1 do tabla2.fields[iX].value := tabla1.fields[iX].value; tabla2.post; tabla1.next; end;

Pues puedes utilizar un bucle de estos para construir sobre la marcha la sentencia, antes de ejecutarla (ignorando el campo que sabes que va a ser distinto).

Código:

SQL := 'insert into TablaB'(;

tablaA.open;
while not tablaA.eof do begin
  for iX = 0 to tablaA.fields.count-1 do SQL := SQL + tablaA.fields[iX].FieldName + ', ';
  tablaA.next;
end;

SQL := SQL + ') select * from TablaA';

Conexion.ExecSQL(SQL);

Saludos.

Casimiro Notevi 07-02-2012 18:52:00

Código Delphi [-]
insert into tabla_b
select *, 0 from tabla_a

Pues aparentemente no funciona de ese modo, es lo primero que probé :(

Casimiro Notevi 07-02-2012 18:54:19

Cita:

Empezado por guillotmarc (Mensaje 424422)
Hola Casimiro.
Pues puedes utilizar un bucle de estos para construir sobre la marcha la sentencia, antes de ejecutarla (ignorando el campo que sabes que va a ser distinto).
Saludos.

Hola, sí, desde delphi no hay problema, es que quiero hacerlo en la base de datos, desde un stored procedure, por ejemplo.

roman 07-02-2012 19:00:30

Cita:

Empezado por Casimiro Notevi (Mensaje 424423)
Código Delphi [-]
insert into tabla_b
select *, 0 from tabla_a

Pues aparentemente no funciona de ese modo, es lo primero que probé :(

Ya, pues..., ni qué decir que en MySQL funciona a la perfección :p

// Saludos

guillotmarc 07-02-2012 19:02:14

Cita:

Empezado por Casimiro Notevi (Mensaje 424426)
Hola, sí, desde delphi no hay problema, es que quiero hacerlo en la base de datos, desde un stored procedure, por ejemplo.

Entonces puedes hacer lo mismo en el procedimiento almacenado, consultando las tablas de sistema para obtener los nombres de los campos, y construyendo una sentencia SQL a ejecutar en un EXECUTE STATEMENT (no soy muy aficionado a construir sentencias dinámicamente, pero no parece que en este caso tengas más opciones).

guillotmarc 07-02-2012 19:04:43

Cita:

Empezado por Casimiro Notevi (Mensaje 424423)
Código:

insert into tabla_b select *, 0 from tabla_a
Pues aparentemente no funciona de ese modo, es lo primero que probé :(

Debería funcionar correctamente, yo lo utilizo en ocasiones. Pruébalo de esta forma (con el alias de la tabla donde hay que coger todos los campos) :

Código:

insert into tabla_b select 0, tabla_a.* from tabla_a
Saludos.

Casimiro Notevi 07-02-2012 19:09:03

Cita:

Empezado por roman (Mensaje 424428)
Ya, pues..., ni qué decir que en MySQL funciona a la perfección :p// Saludos

Sabía que ese iba a ser tu siguiente comentario :D


Cita:

Empezado por guillotmarc (Mensaje 424429)
Entonces puedes hacer lo mismo en el procedimiento almacenado, consultando las tablas de sistema para obtener los nombres de los campos, y construyendo una sentencia SQL a ejecutar en un EXECUTE STATEMENT (no soy muy aficionado a construir sentencias dinámicamente, pero no parece que en este caso tengas más opciones).

Parece que va a ser la solución, aunque tampoco me gusta mucho.

Casimiro Notevi 07-02-2012 19:13:38

¡¡¡ FUNCIONA !!!

Cómo he sido tan burro de no probar con alias.

Código SQL [-]
insert into tabla-B
select 0, a.* from tabla-A a

Casimiro Notevi 07-02-2012 19:15:25

Román, con firebird también se puede, ja, ja, ja... :D


¡¡¡ Gracias a todos, amigos !!! :)

Caral 07-02-2012 19:17:53

Hola
Pero esto no le va a poner un 0 al campo0 ?.
Osea, cero en todos los items ?.
Saludos

Casimiro Notevi 07-02-2012 19:22:46

Cita:

Empezado por Caral (Mensaje 424438)
Hola
Pero esto no le va a poner un 0 al campo0 ?.
Osea, cero en todos los items ?.
Saludos

Bueno, puedes poner el valor que quieras, en mi caso es un número de un generador:
1. Extraer el número que toca, desde un generador
2. Ejecutar la sentencia.

Más o menos así: ejemplo:

Código SQL [-]
iID = GEN_ID(GEN_GLOBAL,1);

insert into tbapunteshistorico
select iID, a.* from tbapuntes a

Supongo que funcionará, voy a probarlo.

Caral 07-02-2012 19:24:12

Hola
Ah, ya decía yo que había gato encerrado en esto.:D:D
Saludos

Caral 07-02-2012 19:36:58

Hola
Este tema lo deberías marcar aquí en Firebird.
Es muy interesante y educativo (todo un tutorial)
Por lo menos yo he aprendido muchísimo.
Saludos

Casimiro Notevi 07-02-2012 19:41:56

Pues lo ponemos, así está más a mano :)

fjcg02 08-02-2012 08:32:05

Código SQL [-]
SET TERM ^ ;

CREATE OR ALTER PROCEDURE PRUEBA 
returns (
    consulta1 varchar(500))
as
declare variable consulta varchar(500);
declare variable campo varchar(250);
begin
  /* Procedure Text */
 CONSULTA1= 'INSERT INTO TABLA1 ';
 CONSULTA = ' SELECT ';
  for select f.rdb$field_name
    from rdb$relation_fields f
    left join rdb$fields fs on fs.rdb$field_name = f.rdb$field_source
    left join rdb$field_dimensions d on d.rdb$field_name = fs.rdb$field_name
    left join rdb$character_sets cr on fs.rdb$character_set_id = cr.rdb$character_set_id
    left join rdb$collations co on ((f.rdb$collation_id = co.rdb$collation_id) and
    (fs.rdb$character_set_id = co.rdb$character_set_id))
    where f.rdb$relation_name = 'TABLA1'
    order by f.rdb$field_position, d.rdb$dimension
    into :CAMPO
    do
     begin
       CONSULTA= CONSULTA||TRIM(CAMPO)||',' ;
       --suspend;
     end
     CONSULTA1=CONSULTA1||CONSULTA||' from TABLA2';
end^

Poniendo un par de parámetros que sean el nombre de la tabla y el del generador, no creo que sea demasiado difícil terminar el procedimiento.
Faltaría quitar la última coma de la relación de campos, pero lo dejo como ejercicio para los principiantes :D:D:D

Saludos
PD: Por supuesto que algún gurú dirá que se puede optimizar; claro que sí, pero no voy a poner todo el ejercicio resuelto.;)

Casimiro Notevi 08-02-2012 13:37:41

Cita:

Empezado por fjcg02 (Mensaje 424485)
PD: Por supuesto que algún gurú dirá que se puede optimizar; claro que sí, pero no voy a poner todo el ejercicio resuelto.;)

Claro, hombre, deja que trabajen las neuronas de los demás, que se van a atrofiar :)

Bueno, pienso que con todo lo comentado aquí ya puede servir de guía para problemas similares, abarcando distintos enfoques, métodos y formas diferentes de encarar un problema de ese tipo.

Gracias a todos :)

RONPABLO 10-02-2012 04:49:07

Yo uso este query, ahí mando tres datos nuevos, la fecha en que borro, el motivo de haber borrado que entra como parametro y un consecutivo independiente (que a ratos creo que es necesario)... eso sí ya me ha pasado varias cenes el error de crear un campo en TEgresos y no crearla en TEgresos_Borrados pero por lo menos el erro que sale es muy diciente.
Código SQL [-]
insert into TEGRESO_BORRADOS
select A.*, CAST('NOW' AS DATE), :motivoBorrar, gen_id(TEGRESO_RELACION_GEN,1) from TEGRESO a 
where a.ID = :ID

Casimiro Notevi 10-02-2012 09:31:42

Gracias por el aporte, me puede ser de utilidad.

TJose 02-11-2012 01:19:43

Cita:

Empezado por Casimiro Notevi (Mensaje 424372)
¿Quién diría que eres un novato? ;)
Ambas tablas siempre se diferenciarán en un campo. Si una se modifica, entonces la otra también.

Código:

tabla-A
 campo1
 campo2
 campo3
 campo4
 campo5
 campo6
 campo7
 campo8
 ...
 campoXXX

tabla-B
 campo0  <- único campo distinto
 campo1
 campo2
 campo3
 campo4
 campo5
 campo6
 campo7
 campo8
 ...
 campoXXX


Hola Casimiro

¿Por qué modificas la estructura de la tabla?
¿Por cambios en las reglas de negocio o por otra razón?

Saludos
TJose

mightydragonlor 02-11-2012 01:39:34

Pues a mi la mejor solució, por lo compresiva a nivel humano es:

Código SQL [-]
insert into Members (number, name)
  select number, name from NewMembers where Accepted = 1
    union
  select number, name from SuspendedMembers where Vindicated = 1

Sacado de la página de Firebird, lo busqué en google hace mucho tiempo como Insert into select =P

Saludos.

Casimiro Notevi 02-11-2012 01:57:41

Hola, de esta pregunta hace 10 meses, ya casi ni me acuerdo, pero el problema es que lleva un generador también, creo que no la has leido desde el principio ;)

Casimiro Notevi 02-11-2012 02:06:44

Cita:

Empezado por TJose (Mensaje 448535)
Hola Casimiro
¿Por qué modificas la estructura de la tabla?
¿Por cambios en las reglas de negocio o por otra razón?
Saludos
TJose

Sí, por ese motivo, nuevos campos que son necesarios según los clientes van pidiendo nuevas funcionalidades.

mightydragonlor 02-11-2012 02:18:43

Cita:

Empezado por Casimiro Notevi (Mensaje 448537)
Hola, de esta pregunta hace 10 meses, ya casi ni me acuerdo, pero el problema es que lleva un generador también, creo que no la has leido desde el principio ;)

El principio si, pero no todo jajajajjaa =P


La franja horaria es GMT +2. Ahora son las 12:28:26.

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