PDA

Ver la Versión Completa : Dá error "Master has detail records" cuando no debería darlo!


JuanBCT
03-08-2005, 16:30:44
Hola! Después de agotar todas las posibilidades (creo) les vengo a pedir ayuda sobre un tema puntual. Estoy haciendo un programa que "depura" registros que tienen varias tablas dependientes, y una de estas tiene a su vez otras cuatro tablas dependientes.

La estructura de las tablas es así:
- ORDENES.DB (maestro)

de esta dependen
- VALE.DB
- ITEMREP.DB
- ITEMTER.DB
- ITEMTEX.DB
- ITEMOBS.DB
- ITEMMOB.DB
- ITEMCOMB.DB
- NDBNCR.DB

y de esta última dependen
- NITEMMOB.DB
- NITEMREP.DB
- NITEMTER.DB
- NITEMTEX.DB

Primero, de un determinado rango de fechas paso los registros a otro juego de tablas iguales, cuyo nombre tiene una D adelante (ej: DORDENES.DB, DITEMREP.DB, etc.) Esto funciona bien.
Lo que entonces tengo que hacer a continuación es borrar estos registros que acabo de pasar, por lo que borro primero en los NITEM, luego en los que dependen de ORDENES y luego el registro en ORDENES.
Lo corro pero de vez en cuando me tira algún error "Master has detail records", más precisamente cuando intento borrar el NDBNCR (se borran CIENTOS de registros antes de q dé esto, por eso no sé cual es el error, mirándo el registro no descubro nada diferente).
La subrutina de borrado que uso es la siguiente:

Base_serv.ordenes.first;
DatamoduleD.Dordenes.first;
while not DatamoduleD.Dordenes.EOF do
begin
Base_serv.Ordenes.SetKey;
Base_serv.Ordenes['Nro_Orden']:=DatamoduleD.Dordenes['Nro_Orden'];
If Base_serv.Ordenes.GotoKey then
begin
//Borro Orden
//Borra Item NItemRep
Base_serv1.NitemRep.first;
while not Base_serv1.NitemRep.eof do Base_serv1.NitemRep.Delete;
//Borra Item NItemMob
Base_serv1.NitemMob.first;
while not Base_serv1.NitemMob.eof do Base_serv1.NitemMob.Delete;
//Borra Item NItemTer
Base_serv1.NitemTer.first;
while not Base_serv1.NitemTer.eof do Base_serv1.NitemTer.Delete;
//Borra Item NItemTex
Base_serv1.NitemTex.first;
while not Base_serv1.NitemTex.eof do Base_serv1.NitemTex.Delete;
//Borra Item Ndbncr
Base_serv1.Ndbncr.first;
while not Base_serv1.Ndbncr.eof do Base_serv1.Ndbncr.Delete;
//Borra Item Comb
Base_serv.ItemComb.first;
while not Base_serv.ItemComb.eof do Base_serv.ItemComb.Delete;
//Borra Item mano de obra
Base_serv.ItemMob.first;
while not Base_serv.ItemMob.eof do Base_serv.ItemMob.Delete;
//Borra Item observaciones
Base_serv.Itemobs.first;
while not Base_serv.Itemobs.eof do Base_serv.Itemobs.Delete;
//Borra Item tex
Base_serv.Itemtex.first;
while not Base_serv.Itemtex.eof do Base_serv.Itemtex.Delete;
//Borra Item ter
Base_serv.Itemter.first;
while not Base_serv.Itemter.eof do Base_serv.Itemter.Delete;
//Borra Item rep
Base_serv.Itemrep.first;
while not Base_serv.Itemrep.eof do Base_serv.Itemrep.Delete;
//Borra Item Vale
Base_serv1.Vale.first;
while not Base_serv1.Vale.eof do Base_serv1.Vale.Delete;
//Borra Orden
Base_serv.ordenes.Delete;
end;
DatamoduleD.Dordenes.Next;
coolgauge4.Progress:=(DatamoduleD.Dordenes.RecNo*100) div DatamoduleD.Dordenes.RecordCount;
end;


Todas las tablas dependientes tienen el campo ['Nro_Orden'] que es el que las relaciona, a mi me parece que el proceso de borrado está bien (aunque evidentemente no lo está) ¿Se les ocurre algo? Cualquier ayuda u opinión que me puedan brindar será muy apreciada.
Gracias!

Juan

Pd: Disculpen la longitud del mensaje! Traté de explicarme bien.

Lepe
04-08-2005, 15:04:24
Al ver la extensión DB parecen archivos paradox, en este caso, cuando se borra con delete, no se adelanta el puntero al registro activo, sino que decrece, por tanto, no debes usar while not tabla.eof sino más bien
while not tabla.bof o incluso while tabla.RecordCount>0

Otra forma más rapida sería con una consulta de borrado:

const sqlBorrado = ' delete from %s where %s';
var Nombres :array[0..2] of string = ('NITEMTEX.DB','NITEMTER.DB','NITEMREP.DB');

var q:Tquery;
i:integer;
begin
q := Tquery.Create;
try
for i:= low(nombres) to high(nombres) do
begin
if q.Active then q.Close;
q.sql.Text := format(sqlBorrado,[Nombres[i], 'Nro_Orden= 32']);
showmessage(IntToStr(q.ExecSql) + ' Registros borrados de la tabla '+Nombres[i]);
end;
finally
FreeAndNil(q);
end;


Por supuesto, en el array de Nombres, las tablas irían puesta en orden inverso al que tú has redactado, precisamente para evitar el error de Master-Detail.

Sólo un detalle más, la variable Nombres no puede estar declarada en un procedimiento, ya que Delphi no deja inicializar variables en dicho lugar, debes ponerla como variable "global" del módulo.

Edito: Lo he escrito de memoria, si tienes algun problema comentalo.

Un saludo, y espero que todavía te sirva.

JuanBCT
05-08-2005, 21:21:37
Hola Lepe! Gracias por tu respuesta, lo resolví mediante consultas como me sugeriste pero de otra manera:
//========================================================================
// * Hacer exactamente el mismo filtro para c/ tabla y borrar mediante una
// sentencia SQL * =======================================================
//========================================================================
with query15 do
begin
close;
sql.clear;
sql.add ('SELECT * From Ordenes');
sql.add ('Where Estado=:W_Estado and');
sql.add ('f_factura <=:w_hasta');
sql.add ('Order by F_Factura');
Params[0].asstring;
Params[1].asdate;
Params.ParambyName('w_estado').asstring:='Facturada';
Params.ParambyName('w_hasta').asdate:=Datetimepicker2.date;
query15.Active:=true;
open;
first;
end;
//========================================================================
// * Bien, acá tengo separado el grupo de ordenes que necesito. Entonces
// ahora la voy a recorrer e ir borrando sus "dependientes" *
//========================================================================
while not Query15.EOF do
begin
//Borro NITEMREP
with query3 do
begin
close;
Databasename:='servicio';
sql.clear;
sql.add ('DELETE From NItemRep');
sql.add ('Where Nro_Orden=:W_NumeOr');
Params[0].asinteger;
Params.ParambyName('W_NumeOr').asinteger:=query15['Nro_Orden'];
ExecSql;
end;
//Borro NITEMTER
with query4 do
begin
close;
sql.clear;
sql.add ('DELETE from NItemTer');
sql.add ('Where Nro_Orden=:W_NumeOr1');
Params[0].asinteger;
Params.ParambyName('W_NumeOr1').asinteger:=query15['Nro_Orden'];
ExecSql;
end;
//Borro NITEMMOB
with query5 do
begin
close;
sql.clear;
sql.add ('DELETE From NItemMob');
sql.add ('Where Nro_Orden=:W_NumeOr2');
Params[0].asinteger;
Params.ParambyName('W_NumeOr2').asinteger:=query15['Nro_Orden'];
ExecSql;
end;
//Borro NITEMTEX
with query6 do
begin
close;
sql.clear;
sql.add ('DELETE From NItemTex');
sql.add ('Where Nro_Orden=:W_NumeOr3');
Params[0].asinteger;
Params.ParambyName('W_NumeOr3').asinteger:=query15['Nro_Orden'];
ExecSql;
end;
//Borro NDB/NCR
with query7 do
begin
close;
sql.clear;
sql.add ('DELETE From NdbNcr');
sql.add ('Where Orden=:W_NumeOr4');
Params[0].asinteger;
Params.ParambyName('W_NumeOr4').asinteger:=query15['Nro_Orden'];
ExecSql;
end;
//Borro vale
with query8 do
begin
close;
sql.clear;
sql.add ('DELETE From Vale');
sql.add ('Where Nro_Orden=:W_NumeOr5');
Params[0].asinteger;
Params.ParambyName('W_NumeOr5').asinteger:=query15['Nro_Orden'];
ExecSql;
end;
//Borro ItemComb
with query9 do
begin
close;
sql.clear;
sql.add ('DELETE From ItemComb');
sql.add ('Where NroOrden_Combo=:W_NumeOr6');
Params[0].asinteger;
Params.ParambyName('W_NumeOr6').asinteger:=query15['Nro_Orden'];
ExecSql;
end;
//Borro ItemObs
with query10 do
begin
close;
sql.clear;
sql.add ('DELETE From ItemObs');
sql.add ('Where Nro_Orden=:W_NumeOr7');
Params[0].asinteger;
Params.ParambyName('W_NumeOr7').asinteger:=query15['Nro_Orden'];
ExecSql;
end;
//Borro ItemTex
with query11 do
begin
close;
sql.clear;
sql.add ('DELETE From ItemTex');
sql.add ('Where Nro_Orden=:W_NumeOr8');
Params[0].asinteger;
Params.ParambyName('W_NumeOr8').asinteger:=query15['Nro_Orden'];
ExecSql;
end;
//Borro ItemTer
with query12 do
begin
close;
sql.clear;
sql.add ('DELETE From ItemTer');
sql.add ('Where Nro_Orden=:W_NumeOr9');
Params[0].asinteger;
Params.ParambyName('W_NumeOr9').asinteger:=query15['Nro_Orden'];
ExecSql;
end;
//Borro ItemRep
with query13 do
begin
close;
sql.clear;
sql.add ('DELETE From ItemRep');
sql.add ('Where Nro_Orden=:W_NumeOr10');
Params[0].asinteger;
Params.ParambyName('W_NumeOr10').asinteger:=query15['Nro_Orden'];
ExecSql;
end;
//Borro ItemMob
with query14 do
begin
close;
sql.clear;
sql.add ('DELETE From ItemMob');
sql.add ('Where Nro_Orden=:W_NumeOr11');
Params[0].asinteger;
Params.ParambyName('W_NumeOr11').asinteger:=query15['Nro_Orden'];
ExecSql;
end;
//Borro Ordenes
with query16 do
begin
close;
sql.clear;
sql.add ('DELETE From Ordenes');
sql.add ('Where Nro_Orden=:W_NumeOr12');
Params[0].asinteger;
Params.ParambyName('W_NumeOr12').asinteger:=query15['Nro_Orden'];
ExecSql;
end;
//--------------------------------------------------
query15.next;
coolgauge4.Progress:=(Query15.RecNo*100) div Query15.RecordCount;
end;
//---------------------------------------------------
query1.Active:=false;
with query1 do
begin
close;
sql.clear;
sql.add ('SELECT * From Ordenes');
sql.add ('Where Estado=:W_Estado and');
sql.add ('f_factura <=:w_hasta');
sql.add ('Order by F_Factura');
Params[0].asstring;
Params[1].asdate;
Params.ParambyName('w_estado').asstring:='Facturada';
Params.ParambyName('w_hasta').asdate:=Datetimepicker2.date;
query1.Active:=true;
open;
first;
end;

Un poco engorroso... pero funciona! De nuevo, gracias...

Juan

Lepe
06-08-2005, 03:48:37
Creo que deberías eliminar las lineas:

Params[0].asstring;
Params[1].asdate;
Y
Params[0].asinteger;

Que sobran en el código.

Un saludo