2016-04-22 8 views
1

Я пытаюсь получить имя ID и USER из одного запроса, но в то же время я ищу в своем предложении WHERE, если ID существует в другой таблице. Я получил сообщение об ошибке:SQL однострочный подзапрос возвращает более одной строки?

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

Вот как мой взгляд запроса:

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

Моего запрос внутри, где положение возвращает два идентификаторы: 158 и 159 так что эти два не должен быть возвращены в моем запросе, где я Я ищу s.ID и s.LASTFIRST. Что может вызвать эту ошибку?

ответ

4

Использование not in вместо !=

!= или = являются для отдельных идентификаторов и значений, not in и in предназначены для многократного

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

Edit: not in против not exists

Not exists является вполне жизнеспособный вариант как Что ж. На самом деле, лучше not exists, чем not in, если есть возможность значений null в наборе результатов подзапроса. В Oracle существование null приведет к тому, что not in не вернет никаких результатов. Как правило, я использую not in для ID, а не для нулевых столбцов и not exists для всего остального. Может быть, лучше практиковать всегда использовать not exists ... личное предпочтение Я полагаю.

Not exists будет написано так:

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

Performance

В Oracle нет никакой разницы в производительности между использованием not in, not exists или left join.

Источник: 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

Спасибо вам @Aron D. Я пытался использовать НЕ СУЩЕСТВУЕТ, но это не сработало. NOT IN отлично работает. –

+0

'не в' медленно. Есть более быстрые способы выполнения одного и того же. –

+1

@ user3023588 Обновленный ответ для 'не существует' –

2

Это отформатированные комментарий, который не имеет отношения к вашему вопросу.

Это медленно:

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

, потому что вы фильтрации на результат функции.

Это логически эквивалентны и гораздо быстрее:

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

Edit начинается здесь

Аарон двойки ответ говорит, чтобы использовать not in.Вот два быстрых способов сделать то же самое:

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

или

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

Ваша рекомендация - переместить event_id после левого соединения вместо того, чтобы иметь его в подзапросе? Это более эффективно или? –

Смежные вопросы