Gracias a todos por participar.
Nobleza obliga, les dejo como lo hice.
Tuve que optimizar los StoreProc de la base de datos y el codigo, pero funciona bien. En 1 Hs está procesado.
En la Db de Firebird cree 2 tablas temporales (una para cada alicuota) sin indexar, con campo CUIT y ALICUOTA.
Mi tabla del padron principal tiene 3 campos: CUIT / Ali_Percep / Ali_Reten indexado con clave sobre el primero.
El proceso se hace desde el sistema disparando diferentes SP en la DB.
Primero un SP hace el borrado de las tablas temporales.
Luego cargo en un TStringList uno de los archivos para obtener los datos necesarios y almacenarlos en la tabla temporal correspondiente con un proceso similar a este:
<DELPHI>
Código Delphi
[-]var
InicioSesion, FinSesion: TDateTime;
s, m, sMsgErrores, sCuit: string;
sAliPer,sAliRet:string;
MyStringList:TStringList;
n,i,Max:integer;
Begin
InicioSesion:= Now;
MyStringList := TStringList.Create;
i:=0;
progress1.Min:=0;
progress1.Position:=0;
MyStringList.LoadFromFile( 'x:\padron_retenciones.txt' );
progress1.Min:=0;
progress1.Max:= MyStringList.Count;
progress1.Position:=0;
DM.SP100.StoredProcName:='SP_TEMP_PER_INS';
DM.SP101.StoredProcName:='SP_TEMP_RET_INS';
DM.WriteTrans.StartTransaction;
for i:=0 to MyStringList.Count-1 do
begin
Application.ProcessMessages;
s:=MyStringList[i];
sCuit :=Copy(s,30,11);
sAliRet:='0';
sAliPer:='0';
if ( (s[1]='P' ) or (s[1]='R' ) ) then
begin
if (s[1]='P')
then sAliPer:=Copy(s,48,4)
else sAliRet:=Copy(s,48,4);
LInfo.Caption:=Format('Procesando registro %d de %d... (CUIT %s)', [i, Max, sCuit ]);
Pinfo.Refresh;
progress1.Position:= i;
if (s[1]='P') then
begin
DM.SP100.ParamByName('Cuit').AsString := sCuit;
DM.SP100.ParamByName('Alicuota').AsFloat:= StrToCurr(Copy(sAliPer,1,1)+'.'+Copy(sAliPer,3,2));
DM.SP100.Prepare;
DM.SP100.ExecProc;
end
else begin
DM.SP101.ParamByName('Cuit').AsString := sCuit;
DM.SP101.ParamByName('Alicuota').AsFloat:= StrToCurr(Copy(sAliRet,1,1)+'.'+Copy(sAliRet,3,2));
DM.SP101.Prepare;
DM.SP101.ExecProc;
end;
IF ((i mod 500) = 0) THEN
BEGIN
TRY
LInfo.Caption:=Format('Grabando bloque %d/%d...', [i, Max ]);
Pinfo.Refresh;
if (DM.WriteTrans.InTransaction) then
begin
DM.WriteTrans.Commit;
DM.WriteTrans.StartTransaction; end
else DM.WriteTrans.StartTransaction; Except
on E:Exception do
begin
DM.WriteTrans.Rollback;
Bien:= FALSE;
PInfo.Visible:=False;
sMsgErrores:= sMsgErrores + 'Error al grabar bloque de datos.'#13+E.Message;
Break;
end;
End;
END;
end;
end;
if (DM.WriteTrans.InTransaction) then
begin
TRY
DM.WriteTrans.Commit;
Except
on E:Exception do
begin
DM.WriteTrans.Rollback;
Bien:= FALSE;
PInfo.Visible:=False;
sMsgErrores:= sMsgErrores + 'Error al guardar el RESTO.'#13+E.Message;
Break;
end;
End;
end;
Si todo anduvo bien (yo utilizo banderas de status, pero lo anterior puede encapsularse en una funcion que devuelva True/False y obrar en consecuencia) entonces unimos mediante otro SP encargado de unir en el padron definitivo las alicuotas existentes en las dos tablas temporales:
Código Delphi
[-] Linfo.Caption:='Guardando datos. Aguarde...';
PInfo.Refresh;
DM.WriteTrans.StartTransaction;
TRY
DM.SP101.StoredProcName:='';
DM.SP101.StoredProcName:='SP_PADRON_MERGE';
DM.SP101.ExecProc;
DM.WriteTrans.Commit;
Linfo.Caption:='Verificando clientes...';
PInfo.Refresh;
Actualizar_Alicuotas_Clientes;
FinSesion:= Now;
m:= Format('(Tiempo: %s)', [ TimeToStr(FinSesion - InicioSesion) ]);
Linfo.Caption:='Importación Finalizada - ' + m;
PInfo.Refresh;
Application.MessageBox(PChar('Proceso finalizado correctamente.'#13 + m),
'Aviso', MB_OK+MB_ICONINFORMATION);
Except
on E:Exception do
begin
DM.WriteTrans.Rollback;
Bien:= FALSE;
PInfo.Visible:=False;
MessageDlg('Error al actualizar el padrón.'#13#13'Tipo de error:'#13+E.Message, mtError, [mbOk],0);
end;
End;
end;
------
<FIREBIRD>
En la DB, el SP encargado de unir a la tabla del Padron definitivo las alicuotas existentes en las dos tablas temporales es esto:
Código SQL
[-]Create or Alter Procedure SP_PADRON_MERGE
as
declare variable sCUIT char(13);
declare variable nP numeric(6,2);
declare variable nR numeric(6,2);
begin
--Paso 1: borramos padron anterior
execute procedure SP_PADRON_DEL;
--Paso 2: Insertamos toda la tabla de Retenciones
INSERT INTO PADRON (CUIT, ALICUOTA_RETENCION, ALICUOTA_PERCEPCION)
SELECT R.cuit, coalesce(R.alicuota,0), 0
FROM TEMP_RETEN R ;
--Paso 3: Buscamos e insertamos desde tabla Percepciones
For
Select T.cuit, coalesce(T.alicuota,0) From TEMP_PERCEP T
Into :sCUIT, :nP
Do
Begin
Select P.ALICUOTA_RETENCION from PADRON P
Where (P.CUIT = :sCUIT)
Rows 1 to 1
into :nR ;
UPDATE or INSERT INTO PADRON (CUIT, ALICUOTA_RETENCION, ALICUOTA_PERCEPCION)
VALUES (:sCUIT, coalesce(:nR, 0) , coalesce(:nP, 0) )
MATCHING (CUIT);
End
end;
Saludos a la comunidad,