2017-12-17 3 views
1

Ich habe zwei Tabellen, adv_institution und institution. Oracle MERGE verwenden, um Back-zu füllen Datensätze adv_institution von institutioninstitution hat 5000+ Reihen, während adv_institution 1400+ORA-00001: eindeutige Einschränkung (MYUSER.ADI_PK) verletzt

hat ich will. Diese zwei Tabellen haben ungefähr vier Felder, die ich zum Füllen verwenden kann.

Hier ist meine ganze MERGE-Anweisung

merge into 
    adv_institution to_t 
using (
    select 
    uni.*, 
    adv_c.country_cd as con_code_text 
    from 
    (
     select 
     institution_cd, 
     name, 
     institution_status, 
     country_cd 
     from 
     institution uni 
     where 
     uni.institution_status = 'ACTIVE' and 
     uni.country_cd is not null 
     group by 
     institution_cd, 
     name, 
     institution_status, 
     country_cd 
     order by 
     name 
    ) uni, 
    country_cd c_cd, 
    adv_country adv_c 
    where 
    uni.country_cd = c_cd.country_cd and 
    c_cd.description = adv_c.country_cd 
) from_t 
on 
(
    to_t.VENDOR_INSTITUTION_CD = from_t.INSTITUTION_CD or 
    to_t.INSTITUTION_CD = from_t.NAME 
) 
WHEN NOT MATCHED THEN INSERT (
    to_t.INSTITUTION_CD, 
    to_t.INSTITUTION_NAME, 
    to_t.SHORT_NAME, 
    to_t.COUNTRY_CD, 

    to_t.NOTE, 
    to_t.UNIT_TERMINOLOGY, 
    to_t.COURSE_TERMINOLOGY, 
    to_t.CLOSED_IND, 

    to_t.UPDATE_WHO, 
    to_t.UPDATE_ON, 
    to_t.CALLISTA_INSTITUTION_CD 
) 
VALUES (
    from_t.NAME, 
    from_t.NAME, 
    '', 
    from_t.con_code_text, 

    '', 
    'UNIT', 
    'COURSE', 
    'N', 

    'MYUSER', 
    SYSDATE, 
    from_t.institution_cd 
); 

Der Fehler habe ich ist

Fehlerbericht - ORA-00001: eindeutige Einschränkung (MYUSER.ADI_PK) verletzt

ADI_PK Mittel adv_institution.institution_cd ist ein Primärschlüssel und muss eindeutig sein.

Das ist, weil in WHEN NOT MATCHED THEN INSERT gibt es eine Insert-Anweisung. Ich füge from_t.NAME in to_t.INSTITUTION_CD ein.

Es sieht aus wie from_t.NAME den gleichen Wert mindestens zweimal hat, wenn sie in to_t.INSTITUTION_CD

Einfügen Aber ich habe eine Gruppe Aussage sicher from_t.NAME zu machen, ist einzigartig:

(
     select 
     institution_cd, 
     name, 
     institution_status, 
     country_cd 
     from 
     institution uni 
     where 
     uni.institution_status = 'ACTIVE' and 
     uni.country_cd is not null 
     group by 
     institution_cd, 
     name, 
     institution_status, 
     country_cd 
     order by 
     name 
    ) uni 

Ich bin nicht sicher, ich verstehe das Problem richtig. Ich habe alles versucht, was ich kann, aber immer noch kein Glück.

Antwort

0

Ich denke, Ihr Hauptproblem ist mit der Gruppe von.

Bitte beachten Sie folgendes Beispiel:

desc temp_inventory; 
Name     Type 
--------------------- ----------- 
WAREHOUSE_NO   NUMBER(2) 
ITEM_NO    NUMBER(10) 
ITEM_QUANTITY   NUMBER(10) 

WAREHOUSE_NO ITEM_NO ITEM_QUANTITY 
1    1000  100 
1    2000  200 
1    2000  300 

Wenn ich eine Abfrage schreiben, wo ich warehouse_no einzigartig sein will:

select warehouse_no,item_quantity 
from temp_inventory 
group by warehouse_no,item_quantity 

Sein die gleichen drei Reihen gehen zurück .. statt i wollen gruppieren nach ..

select warehouse_no,sum(item_quantity) 
from temp_inventory 
group by warehouse_no 

was machen wird Das warehouse_no in dieser Situation einzigartig!

Auch in Fällen, in denen Sie VARCHAR2-Spalten verwenden, können Sie MAX, MIN als Aggregatfunktionen zusammen mit group by verwenden, um einen eindeutigen Schlüssel in der Abfrage zu erstellen.

Beispiel:

Select object_type, min(object_name) 
from user_objects group by object_type; 

, die die object_type einzigartig machen & Rückkehr nur 1 entsprechenden Objektnamen für sie.

So beachten Sie, dass wenn einige Duplikate sind, am Ende einige Datensätze basierend auf der Aggregatfunktion eliminiert werden.

0

„Aber ich habe eine Gruppe Anweisung, um sicherzustellen, from_t.NAME ist einzigartig:“

Aber Ihre Frage ist das nicht. Es erzeugt eine Reihe von verschiedenen Kombinationen von (institution_cd,name,institution_status,country_cd). Natürlich kann eine solche Menge mehrere Wiederholungen von name enthalten, eine für jeden anderen Wert von country_cd. Da Sie vier Elemente in Ihrem Schlüssel haben, garantieren Sie praktisch, dass Ihr Satz mehrere Vorkommen von name hat.

Sie Verbindung dieser mit dem or in der ON-Bedingungen, was bedeutet, Sie die UNMATCHED Logik auslösen, wenn to_t.VENDOR_INSTITUTION_CD = from_t.INSTITUTION_CD obwohl es bereits ein Datensatz in der Zieltabelle ist, wo to_t.INSTITUTION_CD = from_t.NAME.

Das Problem ist, dass die MERGE-Anweisung atomar ist. Die Datensatzgruppe, die von der USING-Unterabfrage stammt, muss eindeutige Schlüssel enthalten. Wenn Oracle ein zweites Vorkommen der gleichen name in der Ergebnismenge findet, heißt es nicht, Ich habe bereits eine davon zusammengeführt, lassen Sie uns es überspringen. Es muss ORA-00001 schleudern, da Oracle nicht wissen kann, welcher Datensatz gültig ist, welche Kombination von (institution_cd,name,institution_status,country_cd) die richtige ist.

Um dies zu lösen, müssen Sie die USING-Abfrage ändern, um eine Ergebnismenge mit eindeutigen Schlüsseln zu erzeugen. Es ist Ihr Datenmodell, Sie verstehen seine Geschäftsregeln, so dass Sie in der Lage sind, es richtig zu schreiben. Aber vielleicht so etwas wie folgt aus:

select 
    name, 
    max(institution_cd) as institution_cd, 
    institution_status, 
    max(country_cd) as country_cd 
    from (
    institution uni 
    where 
    uni.institution_status = 'ACTIVE' and 
    uni.country_cd is not null 
    group by 
    name, 
    institution_status 
    order by 
    name 
) uni 

Dann können Sie die MERGE ON-Klausel vereinfachen zu:

on 
(
    to_t.INSTITUTION_CD = from_t.NAME 
) 

Die Verwendung von MAX() in der Unterabfrage ist ein unelegant Flickschusterei. Ich hoffe, Sie können bessere Geschäftsregeln anwenden.

Verwandte Themen