不使用 EXISTS 嵌套 case 语句引入子查询时,选择列表中只能指定一个表达式

Posted

技术标签:

【中文标题】不使用 EXISTS 嵌套 case 语句引入子查询时,选择列表中只能指定一个表达式【英文标题】:Only one expression can be specified in the select list when the subquery is not introduced with EXISTS nested case statements 【发布时间】:2013-07-31 19:07:11 【问题描述】:

我正在尝试创建一个查询,以获取活动在下面打开的小时数是我的查询。我正在使用案例陈述,因为它需要考虑到只计算工作日。这是我的总体目标是实际获得那些日子的时间的过程中的一个步骤。因此,例如,如果这些天的天数超过一个计数并乘以 8.. 如果它小于一个,则执行 datediff 小时并获取当天的小时数.. 任何帮助将不胜感激!

但我收到以下错误:

当不使用 EXISTS 引入子查询时,选择列表中只能指定一个表达式。

DECLARE @workdays int
SELECT creationDateTime, 
       closedDateTime,DATEDIFF(dd, creationDateTime, closedDateTime)+1,
       CASE WHEN (DATEDIFF(dd, creationDateTime, closedDateTime)+1 > 1)
            THEN (
                  SELECT creationDateTime ,closedDateTime, 
                    ((DATEDIFF(dd, creationDateTime, closedDateTime)+1)
                      -(DATEDIFF(wk, creationDateTime, closedDateTime) * 2)
                      -(CASE WHEN DATENAME(dw, creationDateTime)
                        = 'Sunday' THEN 1 ELSE 0 END)
                      -(CASE WHEN DATENAME(dw, closedDateTime) 
                        = 'Saturday' THEN 1 ELSE 0 END)
                  )*8 AS workdayhours
                  FROM table.ofevents where closedDateTime IS NOT NULL) END
FROM table.ofevents where closedDateTime IS NOT NULL

【问题讨论】:

CASE 是一个表达式(不是语句),它只返回一个值。它不能像您在此处尝试使用的那样用于控制流量。 【参考方案1】:

正如错误所说,您不能在一个值中选择多于一列。执行 select 语句时:

SELECT A, B, C ...

每个表达式ABC,表示要返回的数据。该列由具有 integerdoublevarchar 等数据类型的值组成。

所以当你这样做时:

SELECT A, B, (SELECT C, D FROM ...) ...

您是在说“我想要一列 As、一列 Bs 和一列 ...”哎呀。您刚刚破坏了 SQL,因为它不知道如何将多个值放在这样的单个单元格中。 (嗯,一些 SQL 变体确实知道如何做到这一点,但并不总是那么简单。)

你可能想要的是:

SELECT A, B, (SELECT C FROM ...), (SELECT D FROM ...) etc.

所以,意思是这样的:

declare @workdays int


 SELECT creationDateTime

      , closedDateTime

      , DATEDIFF(dd, creationDateTime, closedDateTime)+1

      , CASE WHEN (DATEDIFF(dd, creationDateTime, closedDateTime)+1 > 1)
          THEN 
           (SELECT creationDateTime
              as workdayhours
              from table.ofevents where closedDateTime IS NOT NULL)
          END

      , CASE WHEN (DATEDIFF(dd, creationDateTime, closedDateTime)+1 > 1)
          THEN 
           (SELECT closedDateTime
              as workdayhours
              from table.ofevents where closedDateTime IS NOT NULL)
          END

      , CASE WHEN (DATEDIFF(dd, creationDateTime, closedDateTime)+1 > 1)
          THEN ( (DATEDIFF(dd, creationDateTime, closedDateTime)+1 )
                -(DATEDIFF(wk, creationDateTime, closedDateTime) * 2)
                -(CASE WHEN DATENAME(dw, creationDateTime) = 'Sunday' THEN 1 ELSE 0 END)
                -(CASE WHEN DATENAME(dw, closedDateTime) = 'Saturday' THEN 1 ELSE 0 END))*8
              as workdayhours
              from table.ofevents where closedDateTime IS NOT NULL)
          END

   FROM table.ofevents where closedDateTime IS NOT NULL

看看每个子查询如何只选择一个单个值?

但是,我仍然不明白您为什么需要选择“creationDateTime”和“closeDateTime”,因此您可能可以删除这些列。

最后一条建议,因为我经常在人们的 SQL 相关问题中看到这一点。非常深入、非常彻底地问自己,为什么你想让 SQL 做某事。你为什么输入:

   (SELECT creationDateTime ,closedDateTime, 
     ( (DATEDIFF(dd, creationDateTime, closedDateTime)+1 )

为什么creationDateTime 就在closeDateTime 前面,这是什么意思? SQL 是一种声明性语言,您写下您的意图,数据库的工作就是生成与您的意图相匹配的数据。这与大多数命令式编程语言(如 C)不同。在 C 中,您写下如何做某事。对于大多数理解命令式语言的人来说,这使得理解 SQL 变得非常困难。所以,问问自己,为什么你创建了那个子查询,你的目标是什么?

如果我的回答不够,请编辑您的问题以阐明您希望结果查询是什么样子。这是非常重要的。如果你不告诉我们你期望查询返回什么,你怎么能期望告诉数据库,或者期望我们告诉你如何告诉数据库?

【讨论】:

您的查询非常昂贵。它将为结果的每一行多次扫描数据库。 哦,当然。我不确定他们到底为什么要执行他们的子查询。【参考方案2】:

我认为您可以摆脱子查询,其他一切都可以工作:

declare @workdays int


SELECT creationDateTime ,closedDateTime,DATEDIFF(dd, creationDateTime, closedDateTime)+1,

CASE WHEN (DATEDIFF(dd, creationDateTime, closedDateTime)+1 > 1)

THEN 

  (( (DATEDIFF(dd, creationDateTime, closedDateTime)+1 )
  -(DATEDIFF(wk, creationDateTime, closedDateTime) * 2)
  -(CASE WHEN DATENAME(dw, creationDateTime) = 'Sunday' THEN 1 ELSE 0 END)
  -(CASE WHEN DATENAME(dw, closedDateTime) = 'Saturday' THEN 1 ELSE 0 END))*8

  as workdayhours

END


FROM table.ofevents where closedDateTime IS NOT NULL

我“按原样”保留了您的工作日时间逻辑。

【讨论】:

以上是关于不使用 EXISTS 嵌套 case 语句引入子查询时,选择列表中只能指定一个表达式的主要内容,如果未能解决你的问题,请参考以下文章

第四章 MySQL高级查询

不使用 EXISTS 引入子查询时,选择列表中只能指定一个表达式

Select 语句中的 Case 语句中的 Exists 函数需要 FOREVER

带有 Exists 的 WHERE CASE WHEN THEN 语句

将嵌套解码转换为等效的 CASE 语句(需要从 Oracle 转换为 PostgreSQL)

SQL嵌套SELECT语句的用法-