PDA

Ver la Versión Completa : Copiar registro de una Tabla a otra Tabla, sin repetirse


MaMu
27-06-2007, 00:52:44
Despues de 42 horas sin dormir, me encuentro con que no puedo conseguir algo muy sencillo, tengo dos tablas, y quiero añadirle registros de una a la otra, unicamente cuando estos sean distintos, y lo que hago es lo siguiente:
QAux--->Tabla A
QEstadisticas---->Tabla B

Quiero copiar de A en B, solo aquellos registros que no sean identicos a los de B, segun una condicion X.


for h:=0 to QAux.RecordCount-1 do
begin
b:=0;
for j:=0 to QEstadisticas.RecordCount-1 do
begin
if QAux.FieldByName('conceptoDEBE').AsString=QEstadisticas.FieldByName('valor').AsString
then b:=b+1 else b:=b;
QEstadisticas.Next;
end;
if b=0
then begin
QEstadisticas.Insert;
try
QEstadisticas.FieldByName('categoria').AsString:='Gastos Generales';
QEstadisticas.FieldByName('valor').AsString:=QAux.FieldByName('conceptoDEBE').AsString;
QEstadisticas.FieldByName('cantidad').AsInteger:=QAux.FieldByName('cantidad').AsInteger;
QEstadisticas.FieldByName('subtotal').AsCurrency:=QAux.FieldByName('importe').AsCurrency;
QEstadisticas.Post;
except
QEstadisticas.Cancel;
end;
end;
QAux.Next;
end;


Pero me copia aun los que estan repetidos, es decir, son identicos en ambas tablas, A y B.

Que estoy haciendo mal? (ademas de no dormir, pero tengo que terminar si o si para poder tomarme unos dias de descanso)

Saludos

vtdeleon
27-06-2007, 01:57:14
Que base de datos usas?

Lo mejor es usar sentencias SQL!

Insert into TablaA
(Select * from TablaB
Where TablaB.CampoID<>TablaA.CampoID)Sino utiliza Locate para buscar el campo llave.

El codigo b:=b no tiene sentido, quita eso!

MaMu
27-06-2007, 03:02:51
Que base de datos usas?

Lo mejor es usar sentencias SQL!


Código SQL [-] (http://www.clubdelphi.com/foros/#)Insert into TablaA
(Select * from TablaB
Where TablaB.CampoID<>TablaA.CampoID)


Sino utiliza Locate para buscar el campo llave.

El codigo b:=b no tiene sentido, quita eso!

Uso Access, y no uso la sentencia sql, porque las tablas son diferentes, solo comparten 3 campos, cuyos FieldNames son diferentes. Lo que no entiendo, es porque me repite uno de los valores.

seara2005
27-06-2007, 03:09:44
Prueba algo así como esto


procedure TransferirDatos(Sender: TObject);
begin
QAux.First;
While Not(QAux.Eof) do
Begin
If Not(QEstadisticas.Locate('Valor',QAuxConceptoDebe.Value,[loCaseInsensitive])) then
Begin
QEstadisticas.Insert;
try
QEstadisticas.FieldByName('categoria').AsString:='Gastos Generales';
QEstadisticas.FieldByName('valor').AsString:=QAux.FieldByName('conceptoDEBE').AsString;
QEstadisticas.FieldByName('cantidad').AsInteger:=QAux.FieldByName('cantidad').AsInteger;
QEstadisticas.FieldByName('subtotal').AsCurrency:=QAux.FieldByName('importe').AsCurrency;
QEstadisticas.Post;
except
QEstadisticas.Cancel;
end;
End;
QAux.Next;
End;
end;

egostar
27-06-2007, 03:17:08
Haber si esto te puede servir


function TForm1.No_Existe(Dato:String):Bool;
begin
Query1.Close;
Query1.SQL.Text := 'SELECT * FROM ESTADISTICAS WHERE VALOR = :dato';
Query1.ParamByName('Dato').AString := Dato;
Query1.Open;
If RecordsCount = 0 then
Result := True
else Result := False;
end;

........
........
While not QAux.EoF do begin
if No_Existe(QAux.FieldByName('conceptoDEBE').AsString) then begin
QEstadisticas.Insert;
try
QEstadisticas.FieldByName('categoria').AsString:='Gastos Generales';
QEstadisticas.FieldByName('valor').AsString:=QAux.FieldByName('conceptoDEBE').AsString;
QEstadisticas.FieldByName('cantidad').AsInteger:=QAux.FieldByName('cantidad').AsInteger;
QEstadisticas.FieldByName('subtotal').AsCurrency:=QAux.FieldByName('importe').AsCurrency;
QEstadisticas.Post;
except
QEstadisticas.Cancel;
end;
end;
QAux.Next;
end;


Aunque lo hice al aire porque no tengo mi Delphi, puede haber algun error.

Salud OS.

Edito: Se me adelanto sara2005, y me parece una muy buena idea la del LOCATE.

vtdeleon
27-06-2007, 04:22:25
Uso Access, y no uso la sentencia sql,Mejor aun, y mas razon para usar las sentencias. porque las tablas son diferentes, solo comparten 3 campos, cuyos FieldNames son diferentesEso no importa.

Danos detalles de las tablas, los campos relacionados, y el campo Id (el cual no queires que se repita).

Neftali [Germán.Estévez]
27-06-2007, 09:42:36
Quiero copiar de A en B, solo aquellos registros que no sean identicos a los de B, segun una condicion X.
Pero me copia aun los que estan repetidos, es decir, son identicos en ambas tablas, A y B.

Lo que veo es que haces dos for anidados para recorrer ambas tablas. Para el primer registro de la primera copiarás todos los de la segunda que son diferentes, pero igual para el segundo de la primera, el tercero de la primera,....

Creo que estás haciendo más recorridos de la cuenta; Recorre una única tabla y dentro de ese busca en la segunda (sea con SQL como te han dicho o con un Locate).

MaMu
27-06-2007, 20:32:39
SOLUCIONADO

Gracias a todos, tome un poco de cada una de las sugerencias de ustedes y logre solucionarlo.

Muchas Gracias

egostar
27-06-2007, 21:04:40
SOLUCIONADO

Gracias a todos, tome un poco de cada una de las sugerencias de ustedes y logre solucionarlo.

Muchas Gracias

Hola mamu

Muchos de nosotros te agradeceriamos que postearas la solución para consultas futuras, de esa manera, quien tenga un problema similar trendrá de primera mano la solución a sus dudas.

Salud OS.

Crashthebig
03-07-2007, 05:17:23
deberas declarar la tabla de la que copiaras los datos con el nombre: tblsource, y la tabla a la que copiaras los datos con el nombre de: tbldest.

y copia este codigo en algun boton

var
i : integer;
fldDest, fldSource : TField;
begin
with tblDest do begin
Append;
for i := 0 to FieldCount - 1 do
begin
fldDest := Fields[i];
if not (fldDest.ReadOnly or fldDest.Calculated) then
begin
fldSource := tblSource.FindField(fldDest.FieldName);
if assigned(fldSource) then
begin
fldDest.DataSet.Edit;
fldDest.AsString := fldSource.AsString
end
end
end;
{Post}
end


esta sentencia copiara el registro activo de la tabla tblsource a la tabla tbldest

Vales08
06-04-2013, 21:24:08
Buenas tardes, me meto en este hilo porque tengo la misma consulta...
Pasar registros de una tabla a otra, pero sin que se repitan. yo lo hago mediante dos dbgrid y en un boton puse el codigo que paso seara2005, lo modifiqué segun mi programa, pero el problema esta en que me carga el registro tantas veces como registros hay cargado en la tabla.. (ejemplo: si tengo 3 registros en total cargado en la tabla principal, me carga el registro 3 veces en la otra tabla).

Como puedo solucionar eso? o que estoy haciendo mal.. Les paso mi codigo para que me puedan ayudar..
DM.Q_alim.First;
While Not(DM.Q_alim.Eof) do
Begin
If Not(DM.Q_plan_y_alim.Locate('ID_ALIM',DM.Q_alimID_ALIM.Value,[loCaseInsensitive])) then
Begin
DM.DSET_plan_y_alim.Insert;
try
DM.DSET_plan_y_alimESTADO.Value:=0;
DM.DSET_plan_y_alim.FieldByName('ID_ALIM').AsInteger:=DM.DSET_alim.FieldByName('ID_ALIM').AsInteger;
DM.DSET_plan_y_alim.FieldByName('ID_PLAN').AsInteger:=DM.DSET_plan_alim.FieldByName('ID_PLAN_A').AsI nteger;
DM.DSET_plan_y_alim.Post;
except
DM.DSET_plan_y_alim.Cancel;
end;
End;
DM.Q_alim.Next;
End;

Aclaro: a la hora de la inserción uso el DataSet porque el Query no me permite el ingreso de registros ya que es de solo lectura.

Muchas gracias

ecfisa
07-04-2013, 00:45:18
Hola Vales08.

También podes pasar registros de una tabla a otra, sin que aquellos se repitan, de este modo:

INSERT INTO TABLA_DESTINO (ID, CP1, CP2 ,...)
SELECT ID, CP1, CP2,...
FROM TABLA_ORIGEN T1
WHERE NOT EXISTS (SELECT T2.ID, T2.CP1, T2.CP2 ,...
FROM TABLA_DESTINO T2
WHERE T1.ID = T2.ID
AND T1.CP1 = T2.CP1
AND T1.CP2 = T2.CP2
...)


Saludos.

Vales08
08-04-2013, 19:13:29
ecfisa muchas gracias por la respuesta..
Eh probado el código pero me salta un error y no se que puede ser..
Error:
Dynamic SQL Error
SQL error code = -804
Count of columns does not equal count of values

El codigo:
DM.Q_plan_y_alim.Active:=False;
with DM.Q_plan_y_alim.SQL do
begin
Clear;
Add('INSERT INTO PLAN_Y_ALIM (ID_PLAN_Y_ALIM, ID_ALIM, ID_PLAN)');
Add('SELECT ID_ALIM ');
Add('FROM ALIMENTOS ');
Add('WHERE NOT EXISTS (SELECT PLAN_Y_ALIM.ID_PLAN_Y_ALIM, PLAN_Y_ALIM.ID_ALIM, PLAN_Y_ALIM.ID_PLAN ');
Add('FROM PLAN_Y_ALIM ');
Add('WHERE ALIMENTOS.ID_ALIM = PLAN_Y_ALIM.ID_ALIM)');
end;
DM.Q_plan_y_alim.Active:=True;

Me gustaria que me orientaras a saber donde puede estar el problema..

ecfisa
08-04-2013, 20:15:18
Hola Vales08.

A primera vista, en la línea:

Add('INSERT INTO PLAN_Y_ALIM (ID_PLAN_Y_ALIM, ID_ALIM, ID_PLAN)');

indicas que vas a insertar valores en tres columnas de la tabla PLAN_Y_ALIM.

Pero en las líneas:

Add('SELECT ID_ALIM');
Add('FROM ALIMENTOS');

Solo seleccionas una columna de la tabla ALIMENTOS, es que decir que faltaría especificar dos columnas de dicha tabla para ser insertados en las columnas ID_ALIM e ID_PLAN de la tabla PLAN_Y_ALIM

Saludos.

Vales08
08-04-2013, 23:03:48
Ahh claro..
Lo que sucede es que en la tabla PLAN_Y_ALIM solo tengo el ID_PLAN_Y_ALIM y luego las forenkey ID_ALIM (Pertenece a la tabla ALIMENTOS) y ID_PLAN (pertenece a la tabla PLANES_ALIM).
Entonces lo que yo necesito es que al seleccionar un registro de la tabla ALIMENTOS, ese registro se guarde en la tabla PLAN_Y_ALIM, donde se genera un ID_PLAN_Y ALIM y se le asigna el ID_ALIM seleccionado y el ID_PLAN de la tabla PLANES_ALIM (ese id sale de un alta que hago antes). No se si se entiende.
el codigo tendria que quedar asi entonces:

DM.Q_plan_y_alim.Active:=False;
with DM.Q_plan_y_alim.SQL do
begin
Clear;
Add('INSERT INTO PLAN_Y_ALIM (ID_ALIM, ID_PLAN)');
Add('SELECT ID_ALIM ');
Add('FROM ALIMENTOS ');
Add('WHERE NOT EXISTS (SELECT PLAN_Y_ALIM.ID_ALIM, PLAN_Y_ALIM.ID_PLAN ');
Add('FROM PLAN_Y_ALIM ');
Add('WHERE ALIMENTOS.ID_ALIM = PLAN_Y_ALIM.ID_ALIM');
Add('AND PLANES_ALIM.ID_PLAN_A = PLAN_Y_ALIM.ID_PLAN)')
end;
DM.Q_plan_y_alim.Active:=True;

Seria mas o menos asi??

ecfisa
08-04-2013, 23:35:29
Hola Vales08.


Si, si el campo ID de la tabla PLAN_Y_ALIM se genéra automáticamente sólo sería necesario completar esos campos.

Pero cuando te referis a:
Entonces lo que yo necesito es que al seleccionar un registro de la tabla ALIMENTOS, ese registro se guarde en la tabla PLAN_Y_ALIM...
No me queda en claro si es lo que estas precisando... Por que la sentencia SQL que te puse en el mensaje #12, copia todos los campos no repetidos de una tabla a otra (que es de lo que se trataba inicialmente el hilo)

Saludos.

Vales08
08-04-2013, 23:43:48
Ahh entonces estoy equivocada con el codigo.. Yo necesito pasar archivos de una tabla a otra sin repetir, pero no todos, si no los que yo voy seleccionando desde una grilla..
Mil disculpas por haber ocupado tu tiempo en algo que no era. Y muchas gracias por tu dedicación.

Neftali [Germán.Estévez]
09-04-2013, 09:05:53
Yo necesito pasar archivos de una tabla a otra sin repetir, pero no todos, si no los que yo voy seleccionando desde una grilla..


En ese caso deberás pasarlos 1 a 1 realizando un recorrido por los que tienes seleccionados en el DBGRid.
Para el recorrido puedes utilizar la propiedad SelectedRows y para cada registro hacer la copia.


var
i: Integer;
begin
if DBGrid1.SelectedRows.Count > 0 then begin
with DBGrid1.DataSource.DataSet do begin
for i := 0 to DBGrid1.SelectedRows.Count-1 do begin
GotoBookmark(Pointer(DBGrid1.SelectedRows.Items[i]));

=> Realizar la copia del registro actual....


end;
end;
end
end;

Vales08
09-04-2013, 15:24:21
Bien y en la parte donde tengo que realizar la copia del registro lo hago con el codigo SQL como el que me habias pasado antes? o hay alguna forma para hacerlo con codigo delphi?

Neftali [Germán.Estévez]
09-04-2013, 17:18:08
Bien y en la parte donde tengo que realizar la copia del registro lo hago con el codigo SQL como el que me habias pasado antes? o hay alguna forma para hacerlo con codigo delphi?

Puedes hacerlo con SQL puedes utilizar una sentencia similar a la de arriba.

Para hacerlo utilizando comandos en Delphi, revisa código como este:



DS.Append;
DS.FieldByName('Codigo').AsString := ACod;
DS.FieldByName('Nombre').AsString := ANombre;
....
DS.Post;

Vales08
10-04-2013, 23:49:04
Muchas gracias Neftali
Bueno les comento que logre hacer lo que necesitaba gracias a ustedes, agregue una linea mas al codigo para evitar que me pasen los registros repetidos.. Le dejo el codigo por si a alguien le llega a hacer falta..
Ahi les va:
var
i, alim, plan: Integer;
begin
if Grilla_plan_a.SelectedRows.Count > 0 then
begin
with Grilla_plan_a.DataSource.DataSet do
begin
for i := 0 to Grilla_plan_a.SelectedRows.Count-1 do
begin
GotoBookmark(Pointer(Grilla_plan_a.SelectedRows.Items[i]));
//para evitar la repetición de los registros a pasar
alim:=DM.DSET_alimID_ALIM.Value;
plan:=DM.DSET_plan_alimID_PLAN_A.Value;
if (DM.Q_plan_y_alim.Locate('ID_ALIM; ID_PLAN', VarArrayOf([alim, plan]), []))then
begin
ShowMessage('El alimento ya ah sido cargado');
end
else
begin
//Abro la tabla pra realizar la inserción y asigno los valores
DM.DSET_plan_y_alim.Append;
DM.DSET_plan_y_alimESTADO.Value:=0;
DM.DSET_plan_y_alimID_ALIM.Value:=DM.DSET_alimID_ALIM.Value;
DM.DSET_plan_y_alimID_PLAN.Value:=DM.DSET_plan_alimID_PLAN_A.Value;
DM.DSET_plan_y_alim.Post;
end;
end;
end;
end;
// esto para que la Grilla2 me vaya mostrando los registros que voy pasando(alimentos) que pertenezcan al plan asignado.
DM.Q_plan_y_alim.SQL.Clear;
DM.Q_plan_y_alim.SQL.Add('select * from PLAN_Y_ALIM where ID_PLAN=:name and ESTADO=0');
DM.Q_plan_y_alim.ParamByName('name').AsInteger:=DM.DSET_plan_y_alimID_PLAN.Value;
DM.Q_plan_y_alim.Open;
DM.DSET_plan_y_alim.Open;

A mi me funciona de maravilla..
Muchisimas gracias por sus aportes, me fueron de gran ayuda..

Neftali [Germán.Estévez]
11-04-2013, 10:07:36
Gracias por compartir el código final.

^\||/

Vales08
11-04-2013, 15:29:11
No es nada... Yo siempre busco ayuda de los demás y es bueno poder compartir lo que uno hizo para ayudar tambien con lo que uno aprende..
Siempre a alguien le hace falta..

Saludos.-