Domanda

Abbiamo una singola tabella che vogliamo spezzare in un albero di tabelle basate su una particolare colonna di origine. Ho voluto provare a utilizzare un inserto a più colonne, ma sembra che se inserisco un blob in una tabella sub, finisco con una violazione del vincolo di chiave esterna.

Non credo che questo viola il regole su inserti multi-tavolo ma potrei sbagliarmi ...

Spero che qualcuno mi potrebbe indicare alcune risorse più approfondita di tutto ciò che sta realmente succedendo qui, in modo che possa essere sicuri che qualsiasi soluzione funzionerà come parte di un insieme di modifiche liquibase su Oracle database 9i -> 11g .

Speriamo semplificato Scenario

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)
 );

Fonte contiene i nostri dati originali. dest sarà la nostra tabella padre, con i bambini e dest_one dest_two (che conterrà informazioni sulle cose di tipo 'uno' o 'due', rispettivamente). Le cose di tipo uno hanno un contenuto, ma le cose di tipo due non lo fanno.

Il tentativo fallì

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');

Come accennato in precedenza, finii con una violazione del vincolo di chiave esterna qui. Per illustrare ulteriormente che il blob era il problema che provato due query simili separati (sotto) realizzando quello senza l'inserto blob lavorato ma con il blob inserto fallito.

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 */

Soluzione 1 - Inserti tradizionale

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 possibilità sto considerando sta tornando a più istruzioni di inserimento separate, ma a differenza di come li ho detto qui, sono preoccupato che dovrò fare in modo che scrivo i miei inserti sub-tavolo per tentare solo inserto quelle righe presenti in tabella genitore dest ... ho bisogno di fare ulteriori ricerche su come Liquibase gestisce più istruzioni SQL nello stesso changeset.

Soluzione 2 - temporaneamente disattivazione dei vincoli di chiave esterna

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;

Questa è la soluzione che sto sporgendosi verso. Mentre disabilitando la chiave esterna sul mio tavolo blob sembra di farlo funzionare nel mio ambiente di test (10g - 10.2.0.1.0), non sono sicuro se devo anche essere invalidante la chiave esterna sul tavolo non blob pure (a causa di come 9i, 11g, o altre versioni di 10g possono comportarsi). Tutte le risorse anche in questo caso sarebbe apprezzato.

Grazie un mazzo!

È stato utile?

Soluzione

Un'altra soluzione potrebbe essere quella di rinviare la valutazione vincolo fino COMMIT. Ho il sospetto (ma non sono sicuro) che l'inserto multi-tavolo è l'inserimento di righe in un ordine diverso da quello che ci si aspetta e desidera. Ricreare i vincoli come segue:

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;

Questa ricrea i vincoli in modo che possano essere differiti e sono differiti dal momento in cui vengono creati. Quindi ritentare l'INSERT originale.

Condividere e godere.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top