Pregunta

Tenemos una sola tabla que queremos que se dividan en un árbol de tablas basadas en una columna de origen particular. Quería probar el uso de un inserto de varias columnas, pero parece que si inserto una burbuja en una mesa sub, termino con una restricción de violación de clave externa.

No creo que esto viola el reglas sobre inserciones de múltiples mesas pero podría estar equivocado ...

Estoy esperando que alguien me podría apuntar a algunos recursos más profundo de todo lo que realmente está pasando aquí, de modo que pueda estar seguro de que cualquier solución que va a funcionar como parte de un conjunto de cambios Liquibase en bases de datos Oracle 9i -> 11 g .

suerte simplificado Escenario

CREATE TABLE source (
    pk NUMBER NOT NULL PRIMARY KEY,
    type VARCHAR2(20) NOT NULL,
    content VARCHAR2(20) NOT NULL
);

INSERT INTO source (pk,type,content) values (1,'two','n/a');
INSERT INTO source (pk,type,content) values (2,'one','Content');

CREATE TABLE dest (
    pk NUMBER NOT NULL PRIMARY KEY,
    type VARCHAR2(20) NOT NULL
);


CREATE TABLE dest_one  (
    pkfk NUMBER NOT NULL PRIMARY KEY,
    data BLOB NOT NULL,
    CONSTRAINT XFK1DEST_ONE FOREIGN KEY (pkfk) REFERENCES dest (pk)
);


CREATE TABLE dest_two  (
    pkfk NUMBER NOT NULL PRIMARY KEY,
    CONSTRAINT XFK1DEST_TWO FOREIGN KEY (pkfk) REFERENCES dest (pk)
 );

Fuente contiene nuestros datos originales. dest será nuestra tabla primaria, con los niños y dest_one dest_two (que contendrá información sobre cosas de 'uno' o 'dos' Tipo). Cosas de un tipo de contenido tienen, pero las cosas de tipo dos no lo hacen.

El intento fallido

INSERT ALL
WHEN 1=1 THEN INTO dest (pk,type) VALUES (pk,type)
WHEN type='one' THEN INTO dest_one (pkfk,data) VALUES (pk,content)
WHEN type='two' THEN INTO dest_two (pkfk) VALUES (pk)
SELECT pk,type,utl_raw.cast_to_raw(content) as content from source where type in ('one','two');

Como se mencionó anteriormente, terminé con una restricción de clave externa violación aquí. Para ilustrar, además, que la mancha era el tema probé dos consultas similares separados (continuación) Para aprovechar el uno sin el inserto burbuja trabajados, con el bloque de inserción fallado.

INSERT ALL
WHEN 1=1 THEN INTO dest (pk,type) VALUES (pk,type)
WHEN type='two' THEN INTO dest_two (pkfk) VALUES (pk)
SELECT pk,type,utl_raw.cast_to_raw(content) as content from source where type = 'two';
/* Successful */

INSERT ALL
WHEN 1=1 THEN INTO dest (pk,type) VALUES (pk,type)
WHEN type='one' THEN INTO dest_one (pkfk,data) VALUES (pk,content)
SELECT pk,type,utl_raw.cast_to_raw(content) as content from source where type = 'one';
/* ORA-02291: integrity constraint violated, no parent key */

Solución 1 - Inserciones tradicionales

INSERT INTO dest (pk,type) SELECT pk,type from source where type in ('one','two');
INSERT INTO dest_two (pkfk) SELECT pk from source where type = 'two';
INSERT INTO dest_one (pkfk,data) SELECT pk,utl_raw.cast_to_raw(content) from source where type = 'one';

Una de las opciones que estoy considerando es volver a múltiples instrucciones de inserción separadas, pero a diferencia de la forma en que los he dicho aquí, me preocupa que voy a tener que asegurarse de que escribo mis inserciones sub-mesa para intentar sólo para insertar esas filas presentan en la tabla padre dest ... necesito hacer más investigaciones sobre cómo Liquibase maneja varias sentencias SQL en el mismo conjunto de cambios.

Solución 2 - Desactivación temporal de restricciones de clave externa

ALTER TABLE dest_one DISABLE CONSTRAINT XFK1DEST_ONE;

INSERT ALL WHEN 1=1 THEN INTO dest (pk,type) VALUES (pk,type) WHEN type='one' THEN INTO dest_one (pkfk,data) VALUES (pk,content) WHEN type='two' THEN INTO dest_two (pkfk) VALUES (pk) SELECT pk,type,utl_raw.cast_to_raw(content) as content from source where type in ('one','two');

ALTER TABLE dest_one ENABLE CONSTRAINT XFK1DEST_ONE;

Esta es la solución que estoy inclinando hacia. Mientras que la desactivación de la clave externa en mi mesa blob parece hacer que funcione en mi entorno de prueba (10 g - 10.2.0.1.0), no estoy seguro de si también debería ser incapacitante la clave externa en la tabla no mancha, así (debido a la forma en 9i, 11g, u otras versiones de 10g pueden comportarse). Cualquier recurso también en este caso sería apreciada.

Gracias un montón!

¿Fue útil?

Solución

Otra solución sería aplazar la evaluación restricción hasta COMMIT. Sospecho (pero no estoy seguro) que el inserto multi-mesa es la inserción de filas en un orden distinto del que espera y desea. Volver a crear las limitaciones de la siguiente manera:

ALTER TABLE DEST_ONE DROP CONSTRAINT XFK1DEST_ONE;

ALTER TABLE DEST_ONE
  ADD CONSTRAINT XFK1DEST_ONE
    FOREIGN KEY (pkfk) REFERENCES dest (pk) 
    INITIALLY DEFERRED DEFERRABLE;

ALTER TABLE DEST_TWO DROP CONSTRAINT XFK1DEST_TWO;

ALTER TABLE DEST_TWO
  ADD CONSTRAINT XFK1DEST_TWO
    FOREIGN KEY (pkfk) REFERENCES dest (pk)
    INITIALLY DEFERRED DEFERRABLE;

Esto vuelve a crear las restricciones para que puedan ser diferidos, y se difieren desde el momento en que son creados. A continuación, probar su INSERT original de nuevo.

Compartir y disfrutar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top