Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Bases de datos > Firebird e Interbase
Registrarse FAQ Miembros Calendario Guía de estilo Buscar Temas de Hoy Marcar Foros Como Leídos

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 29-08-2011
JXJ JXJ is offline
Miembro
 
Registrado: abr 2005
Posts: 2.475
Poder: 21
JXJ Va por buen camino
Question ¿Firebird Ibexpress y maestro detalle capturar id de registro recien ingresado?

Hola..

estoy haciendo una aplicacion que maneje facturas y sus items
con Firebird Ibexpress y maestro detalle
¿ se puede capturar id de un registro recien ingresado?

ejemplo
factura serie ventassucursal1 folio 00001

cantidad descripcion precio total
2 cajas 10 20
2 sillones 100 20
2 tv LCD 10 000 20 000

yo lo que siempre he hecho es una tabla factura
y otra tabla detalle relacionadas.

en una relacion maestro detalle
basandome en el ID de la factura
y en la tala detalle ese ID de la factura es el que uso para
la Foreing Key.


hago un insert into facturas del encabezado

serie, folio, clienterfc, emisorrfc

como la tabla es autonumerica
se genera el ID_factura igual a 1



y despues hago un

Código SQL [-]
select  id_factura serie, folio, clienterfc,  emisorrfc where serie = ventassucursal1   and folio = 00001  
and clienterfc = jxjxj101010   and emisorrfc = emurisorrfc

y recupero el id_factura
asi

id_factura:= IBQuery1.FieldByName('id_factura').AsInteger;


y ya despues en la tabla detalle
hafo un
loop

Código Delphi [-]
for i = 0 to productosvendidos.recordcount -1 do
begin
     //aqui empiezo a hacer el insert 
// tomando el valor 
   insert into detalle 
      id_factura, cantiad, descripticon, precio, total 
end;

el problema es que siempre lo he hecho asi.
inserto el encabezado de la factura

despues pregunto a la BD por el ID de la factura
que recien ingrese y como no se su id
hago el query que revise
si esta existe con la serie , el folio. el rfcdel emisor, del cliente.

existe alguna forma de
saber el ID o el campo que yo quiera
de una registro recien ingresado. por mi aplicacion.
en este caso
me quiero evitar la query para saber si existe una facuta con
la serie , el folio. el rfcdel emisor, del cliente.
y capturar la respuesta.

usando los componentes ibexpress.
o algun otro

muchas gracias por su atencion.
Responder Con Cita
  #2  
Antiguo 29-08-2011
Avatar de ariefez
ariefez ariefez is offline
Miembro
 
Registrado: sep 2005
Ubicación: Perú - Lima
Posts: 63
Poder: 19
ariefez Va por buen camino
En la ayuda de firebird comentan lo que estas buscando, exactamente en el texto README.returning.txt que se encuentra al instalar firebird en la carpeta: ...\Firebird\doc\sql.extensions

parte del texto

Código SQL [-]
  Scope:
    DSQL, PSQL

  Example(s):
    1. INSERT INTO T1 (F1, F2)
       VALUES (:F1, :F2)
       RETURNING F1, F2 INTO :V1, :V2;
    2. INSERT INTO T2 (F1, F2)
       VALUES (1, 2)
       RETURNING ID INTO :PK;
    3. DELETE FROM T1 WHERE F1 = 1 RETURNING F2;
    4. UPDATE T1 SET F2 = F2 * 10 RETURNING OLD.F2, NEW.F2;
Responder Con Cita
  #3  
Antiguo 29-08-2011
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: jul 2004
Ubicación: Salta, Argentina
Posts: 5.582
Poder: 25
Delphius Va camino a la fama
Cita:
Empezado por ariefez Ver Mensaje
En la ayuda de firebird comentan lo que estas buscando, exactamente en el texto README.returning.txt que se encuentra al instalar firebird en la carpeta: ...\Firebird\doc\sql.extensions

parte del texto

Código SQL [-]
  Scope:
    DSQL, PSQL

  Example(s):
    1. INSERT INTO T1 (F1, F2)
       VALUES (:F1, :F2)
       RETURNING F1, F2 INTO :V1, :V2;
    2. INSERT INTO T2 (F1, F2)
       VALUES (1, 2)
       RETURNING ID INTO :PK;
    3. DELETE FROM T1 WHERE F1 = 1 RETURNING F2;
    4. UPDATE T1 SET F2 = F2 * 10 RETURNING OLD.F2, NEW.F2;
Eso no se puede hacer a través de Delphi. Los componentes no soportan la cláusula returning; no al menos lo que vienen de fábrica. O toca esperar a que en una nueva versión se incluya dicho soporte, o bien se utiliza algún componente de tercero que si lo haga (aunque creo que tampco se ha dado).
Además, sólo es viable en Firebird 2.1 y 2.5.

Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #4  
Antiguo 29-08-2011
Avatar de Antoniov
Antoniov Antoniov is offline
Miembro
NULL
 
Registrado: ago 2011
Ubicación: Tenerife
Posts: 42
Poder: 0
Antoniov Va por buen camino
Y todavía Marteens nos puede ayudar ....

Lo más sencillo es usar generadores en Firebird.

Te pongo un extracto del libro de Marteens perteneciente a la Cara Oculta de Delphi 6 (puedes descargarlo en pdf de muchas webs) , que aunque no es actual te puede servir perfectamente.

Generadores
Los generadores (generators) son un recurso de InterBase para poder disponer de valores secuenciales, que pueden utilizarse, entre otras cosas, para garantizar la unicidad de las claves artificiales. Un generador se crea, del mismo modo que los procedimientos almacenados y triggers, en un fichero script de SQL. El siguiente ejemplo muestra cómo crear un generador:
create generator CodigoEmpleado;
Un generador define una variable interna persistente, cuyo tipo es un entero de 32 bits. Aunque esta variable se inicializa automáticamente a 0, tenemos una instrucción para cambiar el valor de un generador:
set generator CodigoEmpleado to 1000;
Por el contrario, no existe una instrucción específica que nos permita eliminar un generador. Esta operación debemos realizarla directamente en la tabla del sistema que contiene las definiciones y valores de todos los generadores:
delete from rdb$generators
where rdb$generator_name = 'CODIGOEMPLEADO'
Para utilizar un generador necesitamos la función gen_id. Esta función utiliza dos parámetros. El primero es el nombre del generador, y el segundo debe ser la cantidad en la que se incrementa o decrementa la memoria del generador. La función retorna Procedimientos almacenados y triggers 245
entonces el valor ya actualizado. Utilizaremos el generador anterior para suministrar automáticamente un código de empleado si la instrucción insert no lo hace:
create trigger NuevoEmpleado for Empleados
active before insert
as
begin
if (new.Codigo is null) then
new.Codigo = gen_id(CodigoEmpleado, 1);
end ^
Al preguntar primeramente si el código del nuevo empleado es nulo, estamos permi-tiendo la posibilidad de asignar manualmente un código de empleado durante la in-serción.
Los programas escritos en Delphi con el BDE tienen problemas cuando se asigna la clave primaria de una fila dentro de un trigger utilizando un generador, pues el registro recién insertado “desaparece” según el punto de vista de la tabla. Este problema se presenta sólo cuando estamos navegando simultáneamente sobre la tabla.
Para no tener que abandonar los generadores, una de las soluciones consiste en crear un procedimiento almacenado que obtenga el próximo valor del generador, y utilizar este valor para asignarlo a la clave primaria en el evento BeforePost de la tabla. En el lado del servidor se programaría algo parecido a lo siguiente:
create procedure ProximoCodigo returns (Cod integer) as
begin
Cod = gen_id(CodigoEmpleado);
end ^
En la aplicación crearíamos un componente spProximoCodigo, de la clase TStoredProc, y lo aprovecharíamos de esta forma en uno de los eventos BeforePost o OnNewRecord de la tabla de clientes:
procedure TmodDatos.tbClientesBeforePost(DataSet: TDataSet);
begin
spProximoCodigo.ExecProc;
tbClientesCodigo.Value :=
spProximoCodigo.ParamByName('COD').AsInteger;
end;
De todos modos, si la tabla cumple determinados requisitos, podemos ahorrarnos trabajo en la aplicación y seguir asignando la clave primaria en el trigger. Las condicio-nes necesarias son las siguientes:
1 La tabla no debe tener columnas con valores default. Así evitamos que el BDE tenga que releer la fila después de su creación.
2 Debe existir un índice único, o casi único, sobre alguna columna alternativa a la clave primaria. La columna de este índice se utilizará entonces como criterio de ordenación para la navegación.
3 El valor de la clave primaria no nos importa realmente, como sucede con las claves artificiales.

Las tablas de referencia que abundan en toda base de datos son un buen ejemplo de la clase de tablas anterior. Por ejemplo, si necesitamos una tabla para los diversos valores del estado civil, probablemente la definamos de este modo:
create table EstadoCivil (
Codigo integer not null primary key,
Descripcion varchar(15) not null unique,
EsperanzaVida integer not null
);
create generator EstadoCivilGen;
set term ^;
create trigger BIEstadoCivil for EstadoCivil
active before insert as
begin
Codigo = gen_id(EstadoCivilGen, 1);
end ^
En Delphi asociaremos una tabla o consulta a la tabla anterior, pero ordenaremos las filas por su descripción, y ocultaremos el campo Codigo, que será asignado automáti-camente en el servidor. Recuerde, en cualquier caso, que los problemas con la asigna-ción de claves primarias en el servidor son realmente problemas de la navegación con el BDE, y nada tienen que ver con InterBase, en sí. Cuando estudiemos DataSnap, además, veremos cómo estos problemas se resuelven con elegancia en este sistema.
NOTA IMPORTANTE
En cualquier caso, si necesita valores únicos y consecutivos en alguna columna de una tabla, no utilice generadores (ni secuencias de Oracle, o identidades de MS SQL Server). El motivo es que los generadores no se bloquean durante las transacciones. Usted pide un valor dentro de una transacción, y le es concedido; todavía no ha termi-nado su transacción. A continuación, otro usuario pide el siguiente valor, y sus deseos se cumplen. Pero entonces usted aborta la transacción, por el motivo que sea. La consecuencia: se pierde el valor que recibió, y se produce un "hueco" en la secuencia.
Responder Con Cita
  #5  
Antiguo 30-08-2011
JXJ JXJ is offline
Miembro
 
Registrado: abr 2005
Posts: 2.475
Poder: 21
JXJ Va por buen camino
ok. muchas gracias.

parece que el unico componente que soporta

RETURNING es el IBDAC
de devart

IBDAC
http://www.crlab.com/ibdac/
InterBase Data Access Components. Comercial, actively developed. Provides extensive functionality and support for new Firebird 2 features like the EXECUTE STATEMENT and the RETURNING clause. A trial version is available for download.

http://www.firebirdfaq.org/faq8/

¿ahora bien. mi metodo esta bien. o puede ser mejorado?

por que lo que escribio

Antoniov

no le entendi.

para lo de hacer claves unicas. o compuestas.

que entiendo seria casi lo mismo pero de forma distinta.

de que hago el insert y luego al db hago un query se
de select

la serie , el folio. el rfcdel emisor, del cliente.
y capturo la respuesta.

como se que los datos son unicos. por la serie y el folio.
y el rfcdelemisor y del receptor. yo confio en que sera la factura que
recien estoy ingresando.

muchas gracias por su atencion.
Responder Con Cita
  #6  
Antiguo 03-09-2011
Avatar de ariefez
ariefez ariefez is offline
Miembro
 
Registrado: sep 2005
Ubicación: Perú - Lima
Posts: 63
Poder: 19
ariefez Va por buen camino
FIBPlus también lo soporta en su tiempo me acuerdo haberlo implementado, pero, luego use generadores, como comentan lineas arriba.

Implementación: mediante un procedimiento obtener el valor del generador en el evento OnBeforePost y luego trabajar con dicho valor según lo requerido, cabe recalcar que uso ClientDataSet en la capa de Entidad y bueno en la Logica uso solo referencias.

El procedimiento para obtener el valor del generador es:

Código SQL [-]
create or alter procedure Proc_Get_Sequence (
    P_SEQ_NAME d_sys_field_name )
returns (
    ID integer )
as
begin
    execute statement
        'select next value for ' || :P_SEQ_NAME || ' from rdb$database'
    into :ID;

    suspend;
end;

O de forma general:

Código SQL [-]
create or alter procedure Proc_Get_Sequence (
    P_TABLE  type of d_sys_relation_name )
returns (
    ID integer )
as
    declare variable vField d_sys_field_name;
begin
    P_TABLE = upper(P_TABLE);

    select rdb$field_name from rdb$relation_fields
        where
            rdb$relation_name = :P_TABLE and
            rdb$field_id = 0
    into :vField;

    if (vField is not null) then
    begin

        vField = 'S_' || vField;

        if ( exists (
                select rdb$generator_name from rdb$generators
                    where rdb$generator_name = :vField ) ) then

            execute statement
                'select next value for ' || :vField || ' from rdb$database'
            into :ID;

    end

    if (ID is null) then
        ID = 0;

    suspend;
end;

Donde:
P_TABLE: Es es nombre de la tabla
d_sys_relation_name: dominio tipo varchar(31)
d_sys_field_name: dominio tipo varchar(31)

El nombre del generador como se puede observar es "S_" || "El nombre del campo", en mi caso siempre es el que se define primero en la tabla (rdb$field_id = 0).

Bueno y otro requerimiento es que exista el generador, sino el procedimiento devolverá cero.

Uso Firebird 2.5, pero creo que también esta disponible para la versión 2.1
Responder Con Cita
Respuesta


Herramientas Buscar en Tema
Buscar en Tema:

Búsqueda Avanzada
Desplegado

Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Duplica registro en ClientDataSet maestro-detalle Josepo Conexión con bases de datos 8 07-05-2013 11:59:09
Maestro detalle con firebird e IBExpress edenis Conexión con bases de datos 1 13-10-2006 19:09:08
Maestro detalle solo muestra un registro jandres Varios 2 10-06-2006 13:11:49
InserciÓn De Registro Con Maestro-detalle perillan Conexión con bases de datos 5 23-10-2005 12:15:23
Cancelar un registro en maestro/detalle... uper Firebird e Interbase 1 15-09-2004 18:56:40


La franja horaria es GMT +2. Ahora son las 10:16:50.


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
Copyright 1996-2007 Club Delphi