SQL单行子查询返回多行?

时间:2016-04-22 15:00:21

标签: sql oracle subquery

我正在尝试从一个查询中获取ID和USER名称,但同时我正在查看我的WHERE子句,如果其他表中存在ID。我收到了错误:

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

我在where子句中的查询返回两个ID:158和159所以这两个不应该在我的查询中返回,我正在寻找s.ID和s.LASTFIRST。什么可能导致此错误?

2 个答案:

答案 0 :(得分:4)

使用not in代替!=

!==适用于单个ID和值,not inin适用于多个

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

修改:not in vs not exists

Not exists也是一个完全可行的选择。实际上,如果子查询结果集中存在not exists值的可能性,则not innull更好 - 在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')

<强>性能

在Oracle中,使用not innot existsleft join之间没有性能差异。

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

  

Oracle的优化器能够看到NOT EXISTS,NOT IN和LEFT JOIN / IS NULL在语义上是等效的,只要列表值被声明为NOT NULL。

     

它对所有三种方法使用相同的执行计划,并且它们同时产生相同的结果。

答案 1 :(得分:2)

这是与您的问题无关的格式化评论。

这很慢:

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

因为您正在过滤函数结果。

这在逻辑上相当且更快:

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

编辑从此处开始

Aaron D的回答是使用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
)