Ir al contenido


Foto

Triggers que escriba y elimine relaciones


  • Por favor identifícate para responder
14 respuestas en este tema

#1 Nikolas

Nikolas

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 604 mensajes
  • LocationMar del Plata / Bs As / Argentina

Escrito 28 mayo 2012 - 01:27

Hola Gente, estoy haciendo un ABM de Artículos en Delphi 7 con Firebird 2.5  *-)

Lo que quiero hacer son 2 triggers que me escriban y eliminen las relaciones.

Mi idea de ellos seria:


1° Trigger (Despues de insertar o modificar)

UPDATE OR INSERT INTO ESDERUBRO
...
UPDATE OR INSERT INTO ESDELINEA
...

(Que escriba o actualice las relaciones con 2 o mas tablas del Articulo actual)

2° Trigger (Antes de eliminar)

DELETE FROM ESDERUBRO WHERE ...

DELETE FROM ESDELINEA  WHERE ...

(Que elimine las relaciones con 2 o mas tablas del Articulo actual)

Las tablas:

Serian:

Artículos
- IDart
- IDRubro
- IDLinea
- ...
- ...

EsDeRubro
- IDart
- IDRubro

EsDeLinea

- IDart
- IDLinea

¿Como lo ven?  :)




Se aceptan: consejos, sugerencias, criticas, comentarios, etc.  (y)


pd: anteriomente lo habia hecho, con consultas separadas desde delphi pero vamos a hacer que trabaje el motor.  :D
  • 0

#2 eduarcol

eduarcol

    Advanced Member

  • Administrador
  • 4.483 mensajes
  • LocationVenezuela

Escrito 28 mayo 2012 - 01:56

no entiendo, que quiere actualizar o eliminar?

  • 0

#3 Nikolas

Nikolas

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 604 mensajes
  • LocationMar del Plata / Bs As / Argentina

Escrito 28 mayo 2012 - 01:59

no entiendo, que quiere actualizar o eliminar?


Las 2 cosas en 2 triggers distintos, cada uno en su evento correspondiente.

  • 0

#4 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 28 mayo 2012 - 03:27

Hola Nikolas,
Ha decir verdad yo tampoco entiendo que es lo que persigues hacer  :(
¿Concretamente, a que te refieres con "eliminar relaciones"? Recuerda la teoría de bases de datos, sobre todo la relacional, que indica que si se ha de permitir eliminar un registro maestro, se rompe el vínculo, enlace o relación con los registros esclavos de éste y por tanto se tiene registros huérfanos. Luego no es posible realizar ninguna operación sobre estos que los asocie derivando en una violación del álgebra relacional.
Si por eliminar relaciones te refieres a eliminar claves foráneas entonces lograr "vincular" y asociar los registros se ha de llevar de forma manual evaluando que el valor del campo que actúa de clave primaria ficticia se corresponda a un campo que actúe de clave foránea ficticio. Es decir, volver a la teoría relacional pero sin hacer explícitamente la relación.
Te pido que por favor te destines el debido tiempo para reordenar tus ideas y volcarlas de una forma más completa. No se te va a cobrar por caracteres. Explícate. ¿Que es lo que en verdad quieres hacer?

Saludos,
  • 0

#5 fredycc

fredycc

    Advanced Member

  • Moderadores
  • PipPipPip
  • 874 mensajes
  • LocationOaxaca, México

Escrito 28 mayo 2012 - 03:41

Yo creo que Nicolas pretende hacer 2 Updates/Insert uno después de otro con la finalidad de crear la relación entre ambas por el detalle de la PK y FK y hacer lo mismo al hacer Delete para que no marque el error que tiene una o más relaciones y por lo tanto no lo permitirá.

Creo hay más formas también:

1) podría ser un SP donde recibas todos los valores para ser insertados en tu tabla, obteniendo el valor del ID através del generador.
2) un Query que haga todo pero en una sola transacción .

Para el hecho del delete me parece existe la opción DELETE ON CASCADE donde especificas la relación para que automático borre registros dependientes y te ahorres su codificación, pero si es necesario registrar en otra tabla el DELETE yo preferiría usar un Trigger.

Espero haber comprendido.

Saludos.
  • 0

#6 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 28 mayo 2012 - 03:55

Hola,
Pues no se si es lo que dices fredycc.
La verdad es que, técnicamente, crear relaciones se HACE UNA VEZ cuando se DISEÑA la tabla. Concretamente, en cuanto uno indica que se está declarando clave foránas que apunten a las primarias y estableciendo los permisos o alcance de propagación (ON CASCADE, etc).

De este modo la relación ya está hecha, a nivel de tabla y no a nivel de datos. Que luego los registros queda relacionados o vinculados es una situación "accidental" causada por la propia teoría relacional.

Eliminar una relación implica justamente romper ésta, a nivel de tablas y no a algo que hace a los registros y altera por consiguiente el diseño de la base de datos con las debidas consecuencias, nada gratas por cierto, de que se ha roto por completo los vínculos de TODOS sus registros y no hay modo de realizar cualquier operación algebraica relacional.

En cuanto leí que Nikolas pretende emplear triggers para "armar y destruir relaciones" sobre un grupo de tablas es que algo no me suena bien.
Si la idea es reasignar los valores de una clave foránea para dicho registro esté vinculado con otro registro maestro, entonces la pregunta está mal dirigida. Eso o es que yo a la teoría de lo que es y conozco por relación ha cambiado estos años.

Por algo pido por favor que Nikolas se explique, no es el primer hilo confuso que leo  ;)

Saludos,
  • 0

#7 Nikolas

Nikolas

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 604 mensajes
  • LocationMar del Plata / Bs As / Argentina

Escrito 28 mayo 2012 - 03:59

Hola Nikolas,
Ha decir verdad yo tampoco entiendo que es lo que persigues hacer  :(


Bien, la idea es justamente respetar la teoría de bdd relacional, borrando físicamente las relaciones que vinculan las tablas en cuestión. (No seria el caso de la baja lógica).

Pongo un ejemplo para ver si logro explicarme correctamente:

Supongamos estos datos cargados:

Tabla ARTICULOS
Art1 - Detalle1 - Linea1Rubro1 - ETC
Art2 - Detalle2 - Linea1- ETC
Art3 - Detalle3 - Linea2- ETC

Tabla LINEAS
Linea1
Linea2
Linea2

Tabla RUBROS
Rubro1
Rubro2
Rubro3

Tabla ESDELINEA (Relación entre artículos y lineas)
Art1 - Linea1
Art2 - Linea1
...

Tabla ESDERUBRO (Relación entre artículos y rubros)
Art1 - Rubro1
Art2 - Rubro2


Ahora:

Dado un caso, donde desee, eliminar fisicamente el "Articulo1"

Borro de la tabla ARTICULOS: los datos del Art1
Lo que quiero hacer el trigger que borre las relaciones de

Tabla ESDELINEA

Art1 - Linea1

y tambien

Tabla ESDERUBRO

Art1 - Rubro1

(y)
  • 0

#8 Nikolas

Nikolas

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 604 mensajes
  • LocationMar del Plata / Bs As / Argentina

Escrito 28 mayo 2012 - 04:06

Yo creo que Nicolas pretende hacer 2 Updates/Insert uno después de otro con la finalidad de crear la relación entre ambas por el detalle de la PK y FK y hacer lo mismo al hacer Delete para que no marque el error que tiene una o más relaciones y por lo tanto no lo permitirá.

Creo hay más formas también:

1) podría ser un SP donde recibas todos los valores para ser insertados en tu tabla, obteniendo el valor del ID através del generador.
2) un Query que haga todo pero en una sola transacción .

Para el hecho del delete me parece existe la opción DELETE ON CASCADE donde especificas la relación para que automático borre registros dependientes y te ahorres su codificación, pero si es necesario registrar en otra tabla el DELETE yo preferiría usar un Trigger.

Espero haber comprendido.

Saludos.


Correcto!

son 2 triggers separados, uno cuando "creo o modifico" y el otro cuando "elimino".


¿Lo que mencionas del SP seria dentro del trigger,no?

gracias!
  • 0

#9 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 28 mayo 2012 - 04:34

Voy a hacer una observación, si me lo permites a tu diseño:

En tu tabla Artículos dispones de los campos IDArt, IDRubro, IDLinea más sus etc. Luego señalas dos tablas "EsDe", una para Rubro y otra para Linea. Cada tabla "EsDe" tiene un campo IDArt y un campo IDxxx siendo xxx la tabla a la que representan.

Ahora bien, en tu último post señalas, además, dos tablas Más: Rubros y Lineas.
Si es como estoy entendiendo tu objetivo es formar dos relaciones (M:M):
Rubros - m ---- m - Articulos - m ---- m - Lineas

De allí que aparezcan estas tablas intermedias "EsDe".

Si mi presunción es correcta, entonces ¿Para que dispones en Artículos de los campos IDRubro e IDLinea? ¡Están sobrando!. Las tablas "EsDe" necesitan de un campo IDEsDeXXX que sea clave primaria... a menos que tu hayas establecido que se trate de una clave compuesta sobre (IDArt, e IDXXX), y por tanto única (que no me creo que sea tu caso).

Como 2do punto, los triggers "DELETE'S" sobran, ya que no hace falta hacerlo por esta vía. Basta con dar permiso de borrado en cascada (ON DELETE CASCADE) para la relación entre Artículos y las EsDe... Más lejos no creo que quieras propagarlo... no creo que quieras que se terminen eliminando los registros de la tabla Rubros y/o Lineas.  *-)
Para el caso de Update también vale... se puede hacer un UPDATE CASCADE.

Saludos,
  • 0

#10 fredycc

fredycc

    Advanced Member

  • Moderadores
  • PipPipPip
  • 874 mensajes
  • LocationOaxaca, México

Escrito 28 mayo 2012 - 04:39

¿Lo que mencionas del SP seria dentro del trigger,no?


No forzosamente, puedes colocar ya sea el Insert/delete en el orden correcto dentro de este y llamarlo, claro vale esto la pena si existen dichas relaciones en tus tablas, el detalle esta en recuperar el ID (PK) con los generadores tratándose de un INSERT y para eliminar solo pasar el ID.

Vale la pena aclarar que si son muchos parámetros no sé, se va ver medio feo, es que luego se juntan demasiado parametros y es dificl interpretar más adelante.

Pero el mismo SP podría borrar o insertar, por ejemplo un parametro llamado Operacion, este recibe "INS"(Insertar), "UPD"(Actualizar), "DEL"(Eliminar) esta validación va en tu SP y junto con demás parámetros harán la magia.

Saludos
  • 0

#11 Nikolas

Nikolas

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 604 mensajes
  • LocationMar del Plata / Bs As / Argentina

Escrito 29 mayo 2012 - 06:27

Voy a hacer una observación, si me lo permites a tu diseño:

En tu tabla Artículos dispones de los campos IDArt, IDRubro, IDLinea más sus etc. Luego señalas dos tablas "EsDe", una para Rubro y otra para Linea. Cada tabla "EsDe" tiene un campo IDArt y un campo IDxxx siendo xxx la tabla a la que representan.

Ahora bien, en tu último post señalas, además, dos tablas Más: Rubros y Lineas.
Si es como estoy entendiendo tu objetivo es formar dos relaciones (M:M):
Rubros - m ---- m - Articulos - m ---- m - Lineas

De allí que aparezcan estas tablas intermedias "EsDe".

Si mi presunción es correcta, entonces ¿Para que dispones en Artículos de los campos IDRubro e IDLinea? ¡Están sobrando!. Las tablas "EsDe" necesitan de un campo IDEsDeXXX que sea clave primaria... a menos que tu hayas establecido que se trate de una clave compuesta sobre (IDArt, e IDXXX), y por tanto única (que no me creo que sea tu caso).

Como 2do punto, los triggers "DELETE'S" sobran, ya que no hace falta hacerlo por esta vía. Basta con dar permiso de borrado en cascada (ON DELETE CASCADE) para la relación entre Artículos y las EsDe... Más lejos no creo que quieras propagarlo... no creo que quieras que se terminen eliminando los registros de la tabla Rubros y/o Lineas.  *-)
Para el caso de Update también vale... se puede hacer un UPDATE CASCADE.

Saludos,


Lo que hice es esto.

Imagen Enviada


¿Lo que mencionas del SP seria dentro del trigger,no?


No forzosamente, puedes colocar ya sea el Insert/delete en el orden correcto dentro de este y llamarlo, claro vale esto la pena si existen dichas relaciones en tus tablas, el detalle esta en recuperar el ID (PK) con los generadores tratándose de un INSERT y para eliminar solo pasar el ID.

Vale la pena aclarar que si son muchos parámetros no sé, se va ver medio feo, es que luego se juntan demasiado parametros y es dificl interpretar más adelante.

Pero el mismo SP podría borrar o insertar, por ejemplo un parametro llamado Operacion, este recibe "INS"(Insertar), "UPD"(Actualizar), "DEL"(Eliminar) esta validación va en tu SP y junto con demás parámetros harán la magia.

Saludos



muy buena idea lo del SP con parametros.

con sus comentarios + esto: http://www.delphiacc...t-firebird-2-1/

voy cerrando la idea.

;)
  • 0

#12 Sergio

Sergio

    Advanced Member

  • Moderadores
  • PipPipPip
  • 1.092 mensajes
  • LocationMurcia, España

Escrito 29 mayo 2012 - 07:43

Como no se a que te refieres con artículos, lineas y rubros, me quedo con el ejemplo del matrimonio y te cuento como hacer automatico que al borrar a una persona se elimine su matrimonio:

Cuando crees la tabla de matrimonios, tendras una relacion con la tabla de hombres, en esa relacion añades "on delete cascade" y listo, al borrar el hombre se borra el matrimonio (y con la mujer igual, claro).

Te copio aqui eso mismo aplicado a una linea de detalle de una factura, que se relaciona con su factura de forma que si la factura se borra, las lineas de detalle se borran "en cascada":


ALTER TABLE FACTURALINEA ADD CONSTRAINT FK_FACTURALINEAFACTURA
  FOREIGN KEY (IDFACTURA) REFERENCES FACTURA (IDFACTURA) ON UPDATE CASCADE ON DELETE CASCADE;


Fijate además que si cambias el identificador de una factura, en cascada se actualizarán tambien todas sus líneas de factura y no se perderá la "conexión" (on update cascade).

Lo de que ocurra algo similar en el alta, eso no lo he pillado... al dar de alta al hombre? a la mujer? al matrimonio?

Fíjate que son 3 tablas y cada una lleva sus triggers, por lo que no hay un trigger común y en ese caso si quieres hacerlo así, usaría un procedure como te han comentado.

Peeero, si das de alta hombre + mujer + matrimonio siempre de un golpe, entonces no entiendo para que lo haces en tres tablas... añade campos a la tabla de matrimonios y listo (algo no estoy entendiendo, seguro).
  • 0

#13 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 29 mayo 2012 - 07:48

No se si me equivoque, pero me da la impresión que podrías estar haciendo un "reproceso" innecesario, quizá por no comprender totalmente el concepto de Integridad Referencial,  voy a tratar de explicarlo con un pequeño ejemplo; observa el siguiente scrpit de creación muy básica de 4 tablas típicas para el manejo de pedidos:


create table CLIENTES (
    IDCliente      INTEGER NOT NULL,
    Cliente          VARCHAR(20),
/*otros campos*/
    primary key    (IDCliente),
);

create table PRODUCTOS (
    IDProducto      INTEGER NOT NULL,
    Producto          VARCHAR(100),
    PrecioVenta      NUMERIC(12,2),
/*OTROS CAMPOS*/

    primary key    (IDProducto)
);

create table PEDIDOS (
    IDPedido        INTEGER NOT NULL,
    IDCliente        INTEGER NOT NULL,
    Fecha            DATE,

    primary key    (IDPedido),
    constraint FK_CLIENTE_PEDIDO
        foreign key (IDCliente) references CLIENTES(IDCliente)
                    on delete no action on update cascade  /*PONER CUIDADO AQUÍ*/
);

create table DETALLES (
    IDDetalle      INTEGER NOT NULL,
    IDPedido      INTEGER NOT NULL,
    IDProducto    INTEGER NOT NULL,
    Cantidad      INTEGER NOT NULL,
    Precio            NUMERIC(12,2),

    primary key    (IDDetalle),
    constraint FK_PEDIDO_DETALLE
        foreign key (IDPedido) references PEDIDOS(IDPedido)
                    on delete cascade on update cascade,  /*PONER CUIDADO AQUÍ*/
    constraint FK_PRODUCTO_DETALLE
        foreign key (IDProducto) references PRODUCTOS(IDProducto)
                    on delete no action on update cascade /*PONER CUIDADO AQUÍ*/
);


Las tablas de Clientes y Pedidos no tiene nada de especial, pero en cambio en la tabla PEDIDOS observa las siguientes líneas:


        foreign key (IDCliente) references CLIENTES(IDCliente)
                    on delete no action on update cascade


La declaración está diciendo literalmente esto: "El valor del campo IDCliente tiene que necesariamente existir en una fila de  la tabla de CLIENTES, y cuando se trate de borrar en la tabla CLIENTES la fila con dicho valor de IDCliente por favor genere una excepción y detenga ese borrado, en cambio si por algún motivo se actualiza dicho campo en la tabla Clientes por favor actualice en la tabla de DETALLES las filas correspondientes con el mismo valor".

Ahora bien ,  observa en la tabla de DETALLES, estas líneas:


    constraint FK_PEDIDO_DETALLE
        foreign key (IDPedido) references PEDIDOS(IDPedido)
                    on delete cascade on update cascade,


La anterior declaración dice literalmente esto: "El valor para el campo IDPedido debe existir necesariamente en la tabla de PEDIDOS, al borrar en la tabla de PEDIDOS la fila con dicho valor para IDPedido, por favor borre en la tabla de DETALLES todos los detalles que contengan dicho valor de IDPedido, igualmente  si se actualiza ese valor en PEDIDOS por favor actualicelos en la tabla de DETALLES.

Con lo descrito anteriormente fácilmente se puede intuir lo que quiere decir la declaración en la relación entre PRODUCTOS y DETALLES.

Ahora bien, como ves, si lo que quieres es borrar las líneas de DETALLES que correspondan  a un PEDIDO borrado, no son necesarios TRIGGERS ni procedimientos almacenados, con las declaraciones anteriores a la hora de crear las tablas es suficiente. Este ejemplo lo puedes extrapolar a tus propias necesidades.

Un cordial saludo.
  • 1

#14 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 29 mayo 2012 - 02:30

Nikolas, la relación 1:1 (uno a uno) es una violación a las reglas normales. La solución básicamente consiste en disponer de una única tabla con los campos de ambas tablas.
El ejemplo que expones de mujer -1---o- Matrimonio -o---1- Hombre  (donde el extremo -o- represente clave compuesta e único) está forzando a formar una clave compuesta y única por lo que se consigue una relación 1:1 conceptual, y me temo que ese ejemplo y la utilización de clave compuesta no es aplicable a tu caso.
Si tu fuerzas a tus relaciones Lineas --> EsDeLinea <-- Artículos y Rubros --> EsDeRubro <-- Artículos a que se basen en la tabla "EsDe" con una clave compuesta estarás manifestando que no sólo cada combinación y dupla de {Linea, Artículo} y {Rubro, Artículo} sea única e irrepetible sino que limitando la posibilidad de cardinalidad.
Seguramente tu esperas que el mismo artículo pueda encontrarse y localizarse en otras instancias de una línea o/o rubro; y a su vez que dado una línea o rubro puedan encontrarse los artículos.
Esto requiere de que se pueda identificar y encontrar cada posible instancia de {linea, Artículo} como de {Rubro, Artículo}. Ahora bien, de allí es que surge un nuevo campo en las tablas intermedias: IDTablaIntermedia que sea clave primaria.

Cuando tu te encuentres con una posible clave compuesta pregúntate si en verdad lo es. La realidad indica que rara vez es necesaria  ;) Te tengo otro motivo, además, por el cual no hacer uso de una clave compuesta: su uso merma el rendimiento, ahora el motor requiere evaluar tantos campos como formen la clave compuesta; no es lo mismo si fuera una clave normal cuyo acceso es rapidísimo.

Los ejemplos que han dado los muchachos demuestran que como dije: los triggers están sobrando, que basta con colocar ON UPDATE CASCADE y/o ON DELETE CASCADE en donde sea necesario el caso.

Mucho me temo que te estás complicando las cosas innecesariamente; o que se suele decir por aquí matar moscas a cañonazos. ¿Porqué no vamos y atacamos el problema de fondo? Te propongo ir a por el diablito que te tiene en esta situación y enfrentarle: ¿Que es lo que en verdad persigues con llevar a cabo toda esta operación? ¿Que funcionalidad lo exige *, requiere? Si vemos el contexto que te ha llevado a este diseño quizá podríamos evaluar alternativas, y que quizá sean más convenientes... después de todo cuando uno está por autorizar un ON DELETE CASCADE debería repensarlo 10 veces.

* Bueno, siendo correctos, si lo exigiera no sería una funcionalidad sino una restricción técnica-operativa.

Saludos,
  • 0

#15 Nikolas

Nikolas

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 604 mensajes
  • LocationMar del Plata / Bs As / Argentina

Escrito 30 mayo 2012 - 09:15

Caballeros, en los últimos 3 comentarios, me han explicado exactamente lo que necesito.

GRACIAS!  (y) (y) (y)
  • 0




IP.Board spam blocked by CleanTalk.