2016-05-19 7 views
0

Ich sehe auf verschiedene Fragen zu diesem Forum zu diesem demselben Thema, dass ein in Dosen und häufig erscheinende Antwort ist:Korreliert Oracle eine Unterabfrage, die auf einer beliebigen Ebene verschachtelt ist?

Nein, Oracle korreliert nicht die Subqueries mehr als eine Ebene tief verschachtelt (und auch nicht MySQL).

Ich würde daraus schließen, dass Oracle korreliert eine Unterabfrage auf einer Ebene tief. Allerdings habe ich das unten stehende Abfrage, und es gibt diese Fehlermeldung:

ORA-00904: „CD“ „FIELD6“. Ungültige Kennung

Diese Abfrage wichtig ist gestaltet, wie es zu sein ist, und ist nur eine vereinfachte Version der tatsächlichen Abfrage, die eine UNION-Anweisung enthält. Beim Debuggen, warum die Fehlermeldung zurückgegeben wurde, reduzierte ich es auf diese einfachste Version (unten). Ich weiß, dass es alternative JOIN-Ansätze für diese einfachste Version geben kann, aber solche alternativen Ansätze würden für die eigentliche Abfrage nicht ausreichen. Wenn das Folgende funktioniert, dann kann scheinbar unsere komplexere Abfrage auch funktionieren. Wenn das Folgende nicht funktioniert, was lese ich dann falsch in der Oracle-Dokumentation und der obigen "Antwort"?

SELECT a.* 
FROM 
    main_detail cd INNER JOIN 
    (
    SELECT 
     Field1, 
     Field2, 
     Field3, 
     Field4, 
     Field5, 
     Field6, 
     Field7 
    FROM other_detail x2 
    WHERE x2.Field1 = cd.Field1 AND x2.Field6 = cd.Field6 
    ) a ON 
    a.Field1 = cd.Field1 
    AND a.Field4 = cd.Field4 
    AND a.Field6 = cd.Field6 

Die unten ist mehr unserem tatsächlichen Bedarf ähnlich. Die Union muss sein, wie es dem JOIN auf der UNION-ed zurückgegeben zu erlauben ist, für welches verwendet wird, um als ein INNER JOIN die Rückkehr Datensatz zu begrenzen:

SELECT h.*, a.* 
FROM 
    header h, 
    (
    SELECT 
     Field1, 
     Field2, 
     Field3, 
     Field4, 
     Field5, 
     Field6, 
     Field7 
    FROM main_detail x1 
    WHERE x1.Field1 = h.Field1 AND x1.Field6 = h.Field6 
    UNION 
    SELECT 
     Field1, 
     Field2, 
     Field3, 
     Field4, 
     Field5, 
     Field6, 
     Field7 
    FROM other_detail x2 
    WHERE x2.Field1 = h.Field1 AND x2.Field6 = h.Field6 
    ) a 
    WHERE 
     a.Field1 = h.Field1 AND 
     a.Field6 = h.Field6 

Wenn die obigen Vergleich zu nicht einschließlich Die korrelierten Unterabfrageparameter und das Testen des Laufs in MS SQL verbessern die Leistung von 9 Minuten auf 30-40 Sekunden, eine sehr beträchtliche Verbesserung. Ich hatte gehofft, die gleichen Gewinne in Oracle zu erleben.

Unten finden Sie so nah wie ich für den eigentlichen Code tun, ohne Kundengeheimnis zu beeinträchtigen:

SELECT DISTINCT 
    c.Field1, 
    c.Field2, 
    D.Field3, 
    b.Field4, 
    b.Field5, 
    c.Field6, 
    c.Field7 || '-' || cds1.Field8 AS status, 
    b.paid, 
    cds.Field8, 
    p.Field9, 
    p.Field10, 
    c.Field11, 
    c.Field12 AS provider_name 
FROM 
    header c, 
    (
    SELECT 
     a.*, 
     cd.paid, 
     cd.Field15, 
     cd.BigList, 
     cd.allowed, 
     cd.copayment, 
     cd.coinsurance 
    FROM 
     header_detail cd, 
     (
     SELECT 
      Field1, 
      Field4, 
      '' AS revenue_code, 
      Field20, 
      Field5, 
      Field14, 
      location_code, 
      ServiceList 
     FROM header_other_detail x1 
     WHERE x1.Field1 = cd.Field1 AND x1.Field14 = cd.Field14 
     UNION 
     SELECT 
      Field1, 
      Field4, 
      revenue_code, 
      Field20, 
      Field5, 
      Field14, 
      '' AS location_code, 
      ServiceList 
     FROM inst_claim_detail x2 
     WHERE x2.Field1 = cd.Field1 AND x2.Field14 = cd.Field14 
     ) a 
    WHERE 
     a.Field1 = cd.Field1 
     AND cd.Field1 = c.Field1 
     AND a.Field20 = cd.Field20 
     AND a.Field14 = cd.Field14 
     AND cd.Field14 = c.Field14a 
    ) b, 
    (
    SELECT 
     Field1, 
     Field14, 
     Trim(
      Trailing ',' FROM 
      ch.icd9_1 || ',' || 
      ch.icd9_2 || ',' || 
      ch.icd9_3 || ',' || 
      ch.icd9_4 || ',' || 
      ch.icd9_5 || ',' || 
      ch.icd9_6 || ',' || 
      ch.icd9_7 || ',' || 
      ch.icd9_8 || ',' || 
      ch.icd9_9 || ',' || 
      ch.icd9_10 || ',' || 
      ch.icd9_11 || ',' || 
      ch.icd9_12 
      ) 
     AS Field3 
    FROM prof_claim ch 
    WHERE ch.Field1 = c.Field1 AND ch.Field14 = c.Field14a 
    UNION 
    SELECT 
     Field1, 
     Field14, 
     Field3 
    FROM inst_claim x3 
    WHERE x3.Field1 = c.Field1 AND x3.Field14 = c.Field14a 
    ) d, 
    (
    SELECT 
     Field1, 
     Field14, 
     Field9, 
     Field10, 
     Field18, 
     refund_amount, 
     Field15 
    FROM payment_detail 
    ) p, 
    (SELECT * FROM Codes WHERE code_type='19') cds, 
    (SELECT * FROM Codes WHERE code_type='28') cds1 
WHERE 
    c.Field17 = 'T00000370' 
    AND c.Field1 = b.Field1 AND c.Field14a = b.Field14 
    AND c.Field1 = d.Field1 AND c.Field14a = d.Field14 
    AND b.Field14 = p.Field14(+) AND b.Field1 = p.Field1(+) AND b.Field15 = p.Field15(+) 
    AND b.BigList = cds.Field16(+) AND b.Field14 = cds.Field14(+) 
    AND c.Field7 = cds1.Field16(+) AND c.Field14a = cds1.Field14(+) 
ORDER BY Field1; 
+0

Oracle 12c unterstützt die Korrelation über mehr als eine Ebene tief. Alle vorhergehenden Versionen nur eine Ebene. – Husqvik

Antwort

1

In der Unterabfrage

SELECT 
    Field1, 
    Field2, 
    Field3, 
    Field4, 
    Field5, 
    Field6, 
    Field7 
FROM other_detail x2 
WHERE x2.Field1 = cd.Field1 AND x2.Field6 = cd.Field6 

Überprüfung der in dem Zustand. Wenn vollständig entfernt oder zumindest die cd Referenz entfernt - die Abfrage funktioniert.

0

Wenn Sie einer Unterabfrage zu einer Tabelle (oder einer anderen Unterabfrage) beitreten, müssen sich alle Join-Bedingungen in der ON-Klausel befinden, wenn Sie ANSI-Joins verwenden.

Der Grund, warum Ihre Abfrage fehlschlägt, liegt daran, dass der Bereich a Unterabfrage nicht außerhalb von sich erstreckt. Es ist völlig unabhängig vom Umfang der main_detail-Tabelle, da Sie versuchen, die Tabellen zu verknüpfen und nicht zu korrelieren. Wie die Antwort von Marmite Bomber nahelegt, muss die Unterabfrage in der Lage sein, eigenständig zu laufen, was Ihre versuchte Version nicht tut.

Was Sie tun müssen, ist die korrelierte Filter zu bewegen, um die ON Klausel, etwa so:

SELECT a.* 
FROM 
    main_detail cd INNER JOIN 
    (
    SELECT 
     Field1, 
     Field2, 
     Field3, 
     Field4, 
     Field5, 
     Field6, 
     Field7 
    FROM other_detail x2) a ON 
    a.Field1 = cd.Field1 
    AND a.Field4 = cd.Field4 
    AND a.Field6 = cd.Field6 
    and a.Field1 = cd.Field1 AND a.Field6 = cd.Field6 

was natürlich ist, identisch mit:

SELECT a.* 
FROM 
    main_detail cd INNER JOIN 
    other_detail a ON 
     a.Field1 = cd.Field1 
     AND a.Field4 = cd.Field4 
     AND a.Field6 = cd.Field6 

Hinsichtlich zu Ihrer Abfrage mit der UNION, sollte dies helfen, Ihnen einen Leistungsvorteil gegenüber Ihrer ursprünglichen Abfrage zu geben:

SELECT * 
FROM (SELECT h1.*, 
       x1.field1, 
       x1.field2, 
       x1.field3, 
       x1.field4, 
       x1.field5, 
       x1.field6, 
       x1.field7 
     FROM main_detail x1 
       inner join header h1 on (x1.Field1 = h1.Field1 AND x1.Field6 = h1.Field6) 
     UNION 
     SELECT h2.* 
       field1, 
       field2, 
       field3, 
       field4, 
       field5, 
       field6, 
       field7 
     FROM other_detail x2 
       inner join header h2 on (x2.Field1 = h2.Field1 AND x2.Field6 = h2.Field6)); 
+0

Ich habe meine Antwort mit einem alternativen Vorschlag aktualisiert. Wie viele Zeilen befinden sich aus Neugier in Ihren Kopf- und Detailtabellen? Erwarten Sie außerdem, dass dieselben Daten sowohl aus Ihrer Haupt- als auch aus anderen Detailtabellen zurückgegeben werden? Wenn die Daten vollständig getrennt sind, können Sie UNION ALL verwenden und eine sort/distinct-Operation speichern. – Boneist

+0

Schön, aber die eigentliche Abfrage hat 8 Subselect-Tabellen und 5 Haupttabellen, so dass es nicht einfach mit Joins durchgeführt werden kann, ohne die Integrität der UNION als begrenzendes Kriterium gegen die Haupttabelle zu verlieren. Also, die UNION ist eine von 4 anderen ähnlichen UNIONEN. Wie im oben genannten Beitrag angegeben, ändert sich die Leistung beim Testen in MS SQL von 9 Minuten auf 30-40 Sekunden. In Oracle dauert die Laufzeit ungefähr 9 Minuten. Wir wollen den gleichen Vorteil erzielen wie MS SQL. –

+0

Wenn Sie Ihre Frage möglicherweise mit einer Beispielabfrage aktualisieren, die Ihre tatsächliche Anfrage genauer widerspiegelt, könnten wir möglicherweise Verbesserungen vorschlagen, die Sie vornehmen könnten. – Boneist