2016-07-28 8 views
-2

Ich kämpfe mit einer Unterabfrage (Oracle 11). Das folgende Beispiel wird für den Zweck der Frage "erfunden".Wie schränkt man die Ergebnisse einer korrelierten Unterabfrage ein, die äußere Abfragealiase verwendet?

Wieder ist dies ein erfundenes Beispiel. Lassen Sie uns keine Diskussionen über Namenskonventionen, Normalisierung oder Altersberechnungen anstellen.

Das Problem ist, dass die korrelierte Abfrage mehrere Ergebnisse zurückgibt und ich muss die erste auswählen. Wenn ich diese korrelierte Abfrage in eine andere umbrechen lasse, um eine select .... where rownum<=1 zu machen, werde ich die Alias-Referenz auflösen.

Bitte arbeiten Sie mit meiner Frage! Wenn Sie versuchen, zu helfen, geben Sie bitte an, wie ich die Ergebnisse der oben genannten Unterabfrage einschränken kann oder dass dies nicht möglich ist. Schreiben Sie diese Abfrage nicht in einige Joins um, da ich nicht in der Lage wäre zu überprüfen, ob Ihre Lösung funktioniert. Wenn die obige Unterabfrage nicht auf eine einzelne Zeile beschränkt werden kann, werde ich die vollständige Abfrage in Joins selbst entwickeln. Bei dieser Frage geht es ausschließlich darum, Ergebnisse einzuschränken, ohne die Alias-Referenz zu unterbrechen.

+1

Wenn Sie schließlich gutes SQL schreiben möchten, müssen Sie mehr Inline-Ansichten als Unterabfragen verwenden. Mit Unterabfragen ist alles eng gekoppelt und schwer zu debuggen. Inline-Ansichten fördern eine lose Kopplung, wodurch es einfacher wird, Aufgaben in unabhängige, verwaltbare Abschnitte aufzuteilen. Das wird mit deinem kleinen Beispiel nicht viel ausmachen.Aber wenn Sie anfangen, riesige Abfragen zu erstellen, macht das einen großen Unterschied. –

Antwort

-1

Die Einschränkungen beim Beantworten schließen Joins aus und setzen die korrelierte Unterabfrage in der SELECT-Klausel fort.

Die Optionen, die ich von sind

  1. Verwenden MAX() oder MIN()
  2. Verwendung denken kann row_number() als
  3. Verwenden Sie eine ORDER BY dann an anderer Stelle gezeigt: OFFSET 0 rows FETCH NEXT-1 ROWS ONLY

ZB

(Select MAX(name) from tablex x 
    where x.id = outer.id) 

für eine Grenze von 1 Sie so etwas wie folgendes tun:

select 
    customer_id 
    , (select cust_last_name 
     from demo_customers c 
     where c.customer_id = o.customer_id 
     ORDER BY c.cust_state desc 
     OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY 
    ) name 
from demo_orders o 

Aber: In diesem Beispiel gibt es einfach keinen guten Grund, nicht eine Verknüpfung zu verwenden, anstatt die weit effizienter wäre.

select 
    o.customer_id 
    , c.cust_last_name 
from demo_orders o 
inner join demo_customers c 
     on c.customer_id = o.customer_id 
+0

Trotz der zur Verfügung gestellten Optionen stimme ich John Heller zu, dass Sie von robusteren und leistungsfähigeren Ansätzen profitieren würden. Die select-Klausel wird übrigens nach der from-Klausel ausgeführt. –

+0

Kann Bestellung nicht verwenden. Zumindest in SQL Developer bekomme ich eine 'ORA-00907: fehlende rechte Klammer'. 'Max()' funktioniert. Sie haben die Frage beantwortet. – user6651485

+0

@ user6651485 ** Brilliant! ** Wird 'MAX (name)' den Namen des ältesten Spielers oder den Namen Zyggy unabhängig von seinem Alter zurückgeben? 'LIMIT 1' existiert in Oracle nicht. Die einzige gültige Antwort ist "' row_number() ', wie ELSEWHERE". Und diese Antwort bekommt "richtige Antwort"! – mathguy

3

So etwas kann funktionieren. Sie benötigen keine korrelierte Unterabfrage, Sie benötigen eine Verknüpfung mit einer ordnungsgemäß definierten Unterabfrage.

Nicht getestet seit (nun, Sie kennen den Rest).

select tm.tmid as team_id, x.first_name || ' ' || x.last_name as oldest_player_name 
    from team tm 
      inner join 
      (select first_name, last_name, tmid,       
         row_number() over (partition by tmid order by age desc) as rn 
      from player) x 
      on tm.tmid = x.tmid 
    where rn = 1; 

Herausgegeben: Wenn Sie eine korrelierte Unterabfrage aus irgendeinem Grund verwenden müssen, können Sie es wie so tun:

SELECT TM.TMID AS TEAM_ID 
    ,(SELECT FIRST_NAME || ' ' || LAST_NAME 
     FROM 
      (select first_name, last_name, tmid, 
          row_number() over (partition by tmid order by age desc) rn 
      from PLAYER 
     )  PL 
     WHERE PL.TMID=TM.TMID 
     AND rn = 1) AS OLDEST_PLAYER_NAME 
FROM TEAM TM 

Der Optimierer sollte klug genug sein, um zu sehen, dass die innerste Unterabfrage konstant ist (nicht korreliert) und nur einmal bewerten.

Verwandte Themen