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 列上应用聚合函数(MINMAX),这将起作用:

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的主要内容,如果未能解决你的问题,请参考以下文章

SQL语句:子查询

sql子查询 嵌套SELECT语句

sql子查询 嵌套SELECT实用语句

sql子查询 嵌套SELECT语句

MYSQL基础九--子查询和连接

MS-Access SELECT TOP N 子查询 SQL