2012-03-22 19 views
6

Tengo tres tablas, llamémoslas GRANDPARENT, PARENT y CHILD. PARENT tiene una columna FK para PK de GRANDPARENT, y CHILD tiene una columna FK para PK de PARENT. Hasta aquí todo bien.¿Cómo configurar una vista actualizable con una unión en Firebird?

Ahora quiero configurar una vista que contiene toda la información en CHILD, más el PK de GRANDPARENT. Entonces:

CREATE VIEW CHILD_VIEW 
(
    ID, 
    PARENT_ID, 
    OTHER_STUFF, 
    GRANDPARENT_ID 
) 
AS 
SELECT 
    C.ID, 
    C.PARENT_ID, 
    C.OTHER_STUFF, 
    C.GRANDPARENT_ID 
FROM CHILD C 
join PARENT P on P.ID = C.PARENT_ID; 

No demasiado difícil. Pero aquí está la parte engañosa: quiero poder INSERT o UPDATE a esta vista, y tener todos los datos relevantes escritos en la tabla CHILD, y el valor GRANDPARENT_ID, si lo hay, debe ignorarse.

He hecho algunas búsquedas en Google y aparentemente debería ser posible configurar una vista actualizable como esta "mediante el uso de disparadores", pero no explica en ningún lado lo que se supone que debo hacer con los desencadenantes para lograr este efecto. Creo que sé más o menos cómo manejar el caso INSERT, pero ¿qué pasa con el caso UPDATE? Las declaraciones UPDATE tienen WHERE cláusulas, y pueden contener o no columnas arbitrarias en la tabla.

Por ejemplo, ¿cómo utilizo un disparador para transformar algo como update CHILD_VIEW set (blah blah blah) where ID = 5 en update CHILD set (blah blah blah excluding GRANDPARENT_ID) where ID = 5?

+0

Buena pregunta acerca de la 'UPDATE' de sólo algunas columnas ... que yo sepa no hay no es forma de detectar qué columnas están incluidas en la instrucción 'UPDATE' que provocó que el disparador' ON UPDATE' se dispare. Creo que vale la pena solicitar una función en el rastreador de Firebird, si no hay uno. – ain

+0

¿No debería en su código 'C.GRANDPARENT_ID' ser' P.GRANDPARENT_ID'? – EMBarbosa

+0

sin vista de tabla múltiple 'INSERT' /' UPDATE's? booooo! –

Respuesta

6

Bueno, lo haces mediante el uso de factores desencadenantes, como ya descubierto :)

Realmente es así de simple, se pueden utilizar todas las funciones disponibles en los disparadores (es decir OLD y NEW contextos) ... si está utilizando Firebird 2.1 o posterior, puede usar la declaración UPDATE OR INSERT, o puede usar las variables de contexto INSERTING y UPDATING para detectar si se actualiza o si se inserta en el activador de acción múltiple. O, por supuesto, se puede escribir por separado ON UPDATE y ON INSERT disparadores ...

Así que su desencadenante podría ser algo como esto

CREATE TRIGGER CHILD_VIEW_Save FOR CHILD_VIEW 
ACTIVE BEFORE INSERT OR UPDATE POSITION 10 
AS 
BEGIN 
    IF(NEW.ID IS NULL)THEN NEW.ID = GEN_ID(GEN_Child, 1); 
    UPDATE OR INSERT INTO CHILD (ID, PARENT_ID, OTHER_STUFF, GRANDPARENT_ID) 
      VALUES(NEW.ID, NEW.PARENT_ID, NEW.OTHER_STUFF, NEW.GRANDPARENT_ID); 
END 
+0

... y ¿qué pasa con la cláusula WHERE cuando se trata de una "ACTUALIZACIÓN"? –

+2

¿Qué tal? Si te refieres al 'donde' en 'UPDATE CHILD_View WHERE' entonces no te importa en el disparador (el disparador se activará para cada fila correspondiente), si te refieres al' WHERE' "dentro del disparador" entonces cualquiera utilice el 'ACTUALIZAR O INSERTAR' o escribir la cláusula WHERE usted mismo (usted conoce el PK de la tabla que está a punto de actualizar dentro del desencadenador). – ain

+0

Bien, buen punto en el PK. El otro truco es un 'UPDATE' que no actualiza todo el conjunto de columnas. Si tengo 5 columnas en la tabla, y la instrucción UPDATE solo establece 3 de ellas, ¿qué hará una manta disparada como su ejemplo a las otras dos columnas? –

Cuestiones relacionadas