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)
-   -   No puedo tomar campo generado automáticamente (https://www.clubdelphi.com/foros/showthread.php?t=77287)

MartinS 11-01-2012 15:10:15

No puedo tomar campo generado automáticamente
 
Hola Foreros: Tengo una consulta que realizar:

Tengo en una base Firebird dos tablas que deseo actualizar en el mismo tiempo pero una debe agregar en un campo el ID de la otra que se genera automáticamente primero.

El caso es el siguiente

Una tabla que tiene la lista de personal,

Id
Legajo
Apellido
Nombre
....

otra guarda las licencias

Id
IdAgente
IdInasistencia // Aqui debo cargar el ID de la tabla de abajo
Tipo
Fecha
....

y otra los días de inasistencia


ID
IdAgente
Periodo
FaltaJust
FaltaInjust
TardeJust
TardeInjust
...

esta ultima guardara tanto las licencias como las inasistencias justificadas o injustificadas) para calcular al año las veces que el empleado a faltado.
Como procedimiento cuando le doy el guardar grabo primero la de inasistencias para que genere el ID (Lo cual lo hace perfectamente) pero no lo puedo tomar (da 0) para cargárselo como referencia a licencias. Espero ser lo bastante claro como para poder tener una solución.-

Fragmento de codigo

Código Delphi [-]
if MessageDlg('¿Confirma el alta de la licencia?',mtConfirmation,mbYesNo,0) = mrYes then
     Begin
       Dm.Inasistencias.FieldByName('IDAgente').AsInteger := CodigoAgente;
       Dm.Inasistencias.FieldByName('tipo').AsString := CTipo.Items.Strings[CTipo.ItemIndex];
       Dm.Inasistencias.FieldByName('FaltaJust').AsInteger := StrToInt(DBEdit1.Text);
       Dm.Inasistencias.FieldByName('Observaciones').AsString := DBEdit2.Text;
       // Las tres lineas siguientes son a modo de desesperacion para ver si me da el bendito ID que genero  
       Dm.Inasistencias.Post;                   
       Dm.Transaccion.CommitRetaining;
       Dm.Inasistencias.Refresh;
       ShowMessage(Dm.Inasistencias.FieldByName('Id').AsString);  // muestra vacio
       Dm.Licencia.FieldByName('IDAGENTE').AsInteger := CodigoAgente;
       Dm.Licencia.FieldByName('IDInasistencia').AsInteger := Dm.Inasistencias.FieldByName('ID').AsInteger;
       Dm.Licencia.FieldByName('Fecha').AsDateTime := Fsolic.DateTime;
       Dm.Licencia.FieldByName('FDesde').AsDateTime := Fdesde.DateTime;
       Dm.Licencia.FieldByName('FHAsta').AsDateTime := FHasta.DateTime;
       Dm.Licencia.Post;
       Dm.Transaccion.CommitRetaining;
  end;

Gracias ;)

oscarac 11-01-2012 16:11:51

no deberia ser

Código Delphi [-]
 ShowMessage(Dm.Inasistencias.FieldByName('IdAGENTE').AsString);

porque el camop ID no lo veo por ningun lugar

MartinS 11-01-2012 16:20:09

El ID de inasistencias no se ve y no le asigno valor porque es generado automáticamente por la base de datos. El tema es tomar ese valor que generó automaticamente para aplicarlo a Licencias. Es como si no se actualizara la tabla de inasistencias....

Chris 11-01-2012 16:37:32

Hola Martín!

Este tema se ha discutido muchas veces acá en el club. Lo que necesitas hacer es averiguar el último ID generado. Hay varias técnicas para hacer esto. Mi preferida es utilizar la clausula RETURNING de SQL. Lamentablemente ésta está disponible a partir de la versión 2.1 de Firebird. Si tienes una anterior no podrás utilizar el código que te proporcionaré a continuación:

Código Delphi [-]
if MessageDlg('¿Confirma el alta de la licencia?',mtConfirmation,mbYesNo,0) = mrYes then
begin
    with Dm.InasistenciasSQL do
    begin
        SQL.Text := 
            'insert into licencias (tipo, FaltaJust, Observaciones) ' +
            'values (:tipo, :faltajust, :observaciones) returning IDAgente';
        
        ParamByName('tipo').AsString := CTipo.Items.Strings[CTipo.ItemIndex];
        ParamByName('FaltaJust').AsInteger := StrToInt(DBEdit1.Text);
        ParamByName('Observaciones').AsString := DBEdit2.Text;
        
        ExecSql;
        
        CodigoAgente := FieldByName('IDAgente').AsInteger; // CodigoAgente es una variable
    end;
    
    // agregar el registro de licencia utilizando el valor de CodigoAgente.
    
    // ...
    
end;

Hay otra técnica que consiste en reservarse de antemano un código dado por el generador. Ese código luego lo utilizas en tu código al agregar nuevos registros. Ten en cuenta que esta técnica solo se aplica en el caso que no es necesario que la consecución de números IDs sea integra. Para obtener un valor de un generador utiliza la clausula GEN_ID de Firebird. Por ejemplo:

Código Delphi [-]
if MessageDlg('¿Confirma el alta de la licencia?',mtConfirmation,mbYesNo,0) = mrYes then
 Begin
    Dm.ObtenerIDQuery.SQL.Text = 'SELECT GEN_ID(GEN_ASISTENCIAS, 1) from RDB$DATABASE;';
    Dm.ObtenerIDQuery.ExecSql;
    CodigoAgente := Dm.ObtenerIDQuery.FieldByName('GEN_ID').AsInteger;
    // Ahora CodigoAgente contiene un número único que acaba de ser reservado.
    
    Dm.Inasistencias.FieldByName('IDAgente').AsInteger := CodigoAgente;
    Dm.Inasistencias.FieldByName('tipo').AsString := CTipo.Items.Strings[CTipo.ItemIndex];
    Dm.Inasistencias.FieldByName('FaltaJust').AsInteger := StrToInt(DBEdit1.Text);
    Dm.Inasistencias.FieldByName('Observaciones').AsString := DBEdit2.Text;
    // Las tres lineas siguientes son a modo de desesperacion para ver si me da el bendito ID que genero  
    Dm.Inasistencias.Post;                   
    
    ShowMessage(Dm.Inasistencias.FieldByName('Id').AsString);  // muestra vacio
    Dm.Licencia.FieldByName('IDAGENTE').AsInteger := CodigoAgente;
    Dm.Licencia.FieldByName('IDInasistencia').AsInteger := Dm.Inasistencias.FieldByName('ID').AsInteger;
    Dm.Licencia.FieldByName('Fecha').AsDateTime := Fsolic.DateTime;
    Dm.Licencia.FieldByName('FDesde').AsDateTime := Fdesde.DateTime;
    Dm.Licencia.FieldByName('FHAsta').AsDateTime := FHasta.DateTime;
    Dm.Licencia.Post;

    Dm.Transaccion.CommitRetaining;
end;

Saludos!

MartinS 11-01-2012 16:50:15

Hola Chris! Gracias por la respuesta.

Mas o menos he comprendido el tema.
CodigoAgente funciona bien ya que es el id del agente que me devuelve una consulta SQL cuando busco a la persona y la selecciono

Ahora bien como se aplicaría la clausula RETURNING dado que Dm.Inasistencias es un IBDataset??? :confused:

Chris 11-01-2012 16:59:40

Cita:

Empezado por MartinS (Mensaje 422736)
Hola Chris! Gracias por la respuesta.

Mas o menos he comprendido el tema.
CodigoAgente funciona bien ya que es el id del agente que me devuelve una consulta SQL cuando busco a la persona y la selecciono

Ahora bien como se aplicaría la clausula RETURNING dado que Dm.Inasistencias es un IBDataset??? :confused:

Tienes que cambiarlo por un TIBQuery. Ahora, si también utilizas el mismo componente para mostrar datos, tendrás que utilizar otra técnica o cambiar la propiedad InsertSQL del TIBDataset por algo similar a lo que te he mostrado.

Saludos,
Chris

MartinS 12-01-2012 14:22:40

Gracias Chris!

Lo he solucionado con la segunda opcion sugerida por ti.


Código Delphi [-]
       Dm.ObtenerIDQUERY.Close;
       Dm.ObtenerIDQUERY.SQL.Clear;
       Dm.ObtenerIDQuery.SQL.Text := 'SELECT GEN_ID(INASISTENCIAS_ID_GEN, 0) from RDB$DATABASE;';
       Dm.ObtenerIDQuery.Open;
       Indice := Dm.ObtenerIDQuery.FieldByName('GEN_ID').AsInteger;

Solo modifique la sentencia dentro del paréntesis del SELECT a 0 porque si no me sumaba uno al que habia generado.
Gracias nuevamente... :D

Saludos !!!

Martin


La franja horaria es GMT +2. Ahora son las 04:10:15.

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