2016-04-22 5 views
1

Ich versuche, ID und USER-Namen von einer Abfrage zu erhalten, aber zur gleichen Zeit schaue ich in meiner WHERE-Klausel, wenn ID in einer anderen Tabelle vorhanden sind. Ich habe Fehler:SQL einreihige Unterabfrage gibt mehr als eine Zeile zurück?

ORA-01427: single-row subquery returns more than one row 

Hier ist, wie meine Abfrage aussehen:

SELECT s.ID, s.LASTFIRST 
From USERS s 
Left Outer Join CALENDAR c 
On s.ID = c.USERID 
Where c.SUPERVISOR = '103' 
And TO_CHAR(c.DATEENROLLED,'fmmm/fmdd/yyyy') >= '4/22/2016' 
And TO_CHAR(c.DATELEFT,'fmmm/fmdd/yyyy') <= '4/22/2016' 
And s.ID != (SELECT USER_ID 
      From RESERVATIONS 
      Where EVENT_ID = '56') 

Meine Abfrage innerhalb der where-Klausel gibt zwei IDs: 158 und 159 so sollten diese beiden nicht in meiner Abfrage zurückgegeben werden, wo ich Ich suche am und am Lasfirst. Was könnte diesen Fehler verursachen?

Antwort

4

Verwenden not in statt !=

!= oder = sind für einzelne IDs und Werte, not in und in sind für mehrere

And s.ID not in (SELECT USER_ID 
       From RESERVATIONS 
       Where EVENT_ID = '56') 

Edit: not in vs not exists

Not exists a vollkommen brauchbare Option als Gut. In der Tat ist es besser, not exists als not in, wenn es die Möglichkeit gibt, null Werte in der Unterabfrage Ergebnismenge - In Oracle, die Existenz eines null wird dazu führen, not in keine Ergebnisse zurückgeben. Als allgemeine Regel verwende ich not in für ID, nicht null Spalten und not exists für alles andere. Es kann besser sein, immer not exists ... persönliche Vorlieben zu verwenden, nehme ich an.

Not exists würde wie so geschrieben werden:

SELECT s.ID, s.LASTFIRST 
From USERS s 
Left Outer Join CALENDAR c 
On s.ID = c.USERID 
Where c.SUPERVISOR = '103' 
And TO_CHAR(c.DATEENROLLED,'fmmm/fmdd/yyyy') >= '4/22/2016' 
And TO_CHAR(c.DATELEFT,'fmmm/fmdd/yyyy') <= '4/22/2016' 
And not exists (SELECT USER_ID 
       From RESERVATIONS r 
       Where r.USER_ID = S.ID 
       And EVENT_ID = '56') 

Leistung

In Oracle gibt es keinen Unterschied in der Leistung zwischen not in, not exists oder left join verwenden.

Quelle: https://explainextended.com/2009/09/17/not-in-vs-not-exists-vs-left-join-is-null-oracle/

Oracle's optimizer is able to see that NOT EXISTS, NOT IN and LEFT JOIN/IS NULL are semantically equivalent as long as the list values are declared as NOT NULL.

It uses same execution plan for all three methods, and they yield same results in same time.

+0

Danke @Aron D. Ich versuchte, nicht zu verwenden VORHANDEN aber das hat nicht funktioniert. NICHT IN funktioniert gut. –

+0

'nicht in' ist langsam. Es gibt schnellere Möglichkeiten, dasselbe zu erreichen. –

+1

@ user3023588 Aktualisierte Antwort für 'nicht existiert' –

2

Dies ist ein formatierte Kommentar, der nicht auf Ihre Frage in Zusammenhang steht.

Dies ist langsam:

And TO_CHAR(c.DATEENROLLED,'fmmm/fmdd/yyyy') >= '4/22/2016' 

, weil Sie auf einem Funktionsergebnis filtern.

Dies ist logisch äquivalent und viel schneller:

And c.DATEENROLLED >= to_date('4/22/2016','fmmm/fmdd/yyyy') 

bearbeiten beginnt hier

Aaron D's Antwort sagt not in zu verwenden.Hier sind zwei schnellere Wege, das Gleiche zu tun:

left join reservations r on s.id = user_id 
and r.event_id = '56' 
etc 
where r.user_id is null 

oder

where s.id in 
(
select user_id 
from reservations 
minus 
select user_id 
from reservations 
where event_id = 56 
)  
+0

Ihre Empfehlung ist es, Event_id nach dem linken Join zu verschieben, anstatt es in der Unterabfrage zu haben? Ist das effizienter oder? –

Verwandte Themen