SQL 在 select 子查询中只返回一行或 null
Posted
技术标签:
【中文标题】SQL 在 select 子查询中只返回一行或 null【英文标题】:SQL return exactly one row or null in a select sub-query 【发布时间】:2013-11-05 20:27:58 【问题描述】:在 Oracle 中,是否可以在 select 语句中有一个子查询,如果子查询恰好返回一行,则返回一列,如果子查询没有返回或返回多于一行,则返回 null ?
例子:
SELECT X,
Y,
Z,
(SELECT W FROM TABLE2 WHERE X = TABLE1.X) /* but return null if 0 or more than 1 rows is returned */
FROM TABLE1;
谢谢!
【问题讨论】:
你可以使用case语句..docs.oracle.com/cd/B19306_01/server.102/b14200/… 【参考方案1】:以不同的方式进行如何?带有子查询的简单 LEFT OUTER JOIN 应该可以满足您的要求:
SELECT T1.X
,T1.Y
,T1.Z
,T2.W
FROM TABLE1 AS T1
LEFT OUTER JOIN (
SELECT X
,W
FROM TABLE2
GROUP BY X,W
HAVING COUNT(X) = 1
) AS T2 ON T2.X = T1.X;
这只会返回恰好有 1 个 X 实例的项目,并在适当的时候将其 LEFT OUTER JOIN 返回到表中(将不匹配项保留为 NULL)。
这也符合 ANSI 标准,因此性能非常好。
【讨论】:
您没有在子查询中选择X
。
糟了!谢谢你@ypercube。我也意识到没有必要分组,因为每个实例的回报总是正好 1。
嗯,很抱歉,但这不会按原样运行。您需要聚合或一些窗口/分析函数向导。你不能只在 SELECT x, w
周围加上 HAVING
子句。
derp 再次...这就是我没有测试的结果哈哈。 HAVING
需要 GROUP BY
。
@PlantTheldea 这几乎可以工作,除了我得到额外的行而不是与 Table1 相同的行数。我尝试了其他类型的连接,但它们都返回比 Table1 略多或略少的行。【参考方案2】:
除了CASE
解决方案或将内联子查询重写为外部联接之外,如果您可以在W
列上应用聚合函数(MIN
或MAX
),这将起作用:
SELECT X,
Y,
Z,
(SELECT MIN(W) FROM TABLE2 WHERE X = TABLE1.X HAVING COUNT(*) = 1) AS W
FROM TABLE1;
【讨论】:
这不需要GROUP BY
。【参考方案3】:
SELECT
X, Y, Z, (SELECT W FROM TABLE2 WHERE X = TABLE1.X HAVING COUNT(*) = 1)
FROM
TABLE1;
【讨论】:
执行此操作需要 group by,当我执行 group by 时,我收到一条错误消息,指出“单行子查询返回多行”。可能值得一提的是,子查询的 where 子句有多个部分。表 1 和表 2 有几个字段需要匹配行,而不仅仅是 W。【参考方案4】:我的回答是:不要使用子选择(除非你确定...)
没有必要也不是一个好主意在这里使用子选择作为 PlantTheIdea 提到的,因为有两件事
解释:
子选择意味着:
对主选择结果集的每一行进行一次选择。即如果你得到 1000 行,你也会在你的数据库系统中得到 1000 个(小)选择状态(这里忽略优化器)
和(!)
使用子选择,您有很好的机会隐藏(或覆盖)繁重的数据库或选择问题。这意味着:您只期望没有(NULL)或一个(完全)行(两者都可以通过 [left outer] 连接轻松解决)。如果您的子选择中有多个有问题,则 SQL 错误指出了这一点
“HAVING COUNT(X) = 1”当然正确,有小(或不小)的问题,那就是:“为什么有超过一行的计数?”
我花了好几个小时寻找这样的解决方法,结果却是“如果你真的确定就不要这样做......”
我认为这与这样的“拥有”相反
...
HAVING date=max(date) -- depends on sql dialect
或
where date = select max(date) from same_table
在我的最后一个示例中,我再次想指出:如果您到达这里不止一行(都从今天开始;。)您遇到了数据库问题 - 例如,您应该使用时间戳
【讨论】:
以上是关于SQL 在 select 子查询中只返回一行或 null的主要内容,如果未能解决你的问题,请参考以下文章