SQL单行子查询returns多行?

SQL single-row subquery returns more than one row?

我正在尝试从一个查询中获取 ID 和 USER 名称,但同时我正在查找我的 WHERE 子句中是否存在其他 table 中的 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 子句 returns 内的查询有两个 ID:158 和 159,因此我在查找 s.ID 和 s.LASTFIRST 的查询中不应返回这两个 ID。什么可能导致此错误?

使用not in代替!=

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

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

编辑:not in 对比 not exists

Not exists 也是一个完全可行的选择。事实上,如果子查询结果集中有null值的可能性,not existsnot in更好——在Oracle中,null的存在会导致not in 到 return 没有结果。作为一般规则,我对 ID 使用 not in,而不是空列,对其他所有内容使用 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'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.

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

这很慢:

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
)