当子查询没有用EXISTS嵌套情况下,选择列表中只能指定一个表达式。

3
我正在尝试创建一个查询,获取事件开放的小时数。以下是我的查询。我使用case语句,因为它需要考虑只计算工作日。这是整个过程中的一步,我的总体目标实际上是获取这些天的小时数。例如,如果天数超过一个,请计算所有这些天并乘以8。如果少于一个,请进行日期差异小时,并仅获取当天的小时数。非常感谢您的帮助!
但是我遇到了以下错误:
当子查询未引入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 是一个表达式(而不是语句),它返回恰好一个值。它不能用于控制流程,就像你在这里尝试使用它一样。 - Aaron Bertrand
2个回答

5

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

SELECT A, B, C ...

每个表达式 A, B, C 代表一个要返回的数据。该列由具有数据类型的值组成,例如integerdoublevarchar
因此,当您执行以下操作时:
SELECT A, B, (SELECT C, D FROM ...) ...

您说:“我想要一列A,一列B,以及一列…”,但是这样会破坏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 )
为什么在closeDateTime之前会有一个creationDateTime,它是什么意思?SQL是一种声明式语言,您写下您的意图,数据库的工作是生成与您的意图相匹配的数据。这与大多数命令式编程语言(如C)不同,在C中,您要写下如何做某件事。这使得理解SQL对于主要理解命令式语言的人来说非常困难。所以,问问自己,为什么要创建那个子查询,你的目标是什么?
如果我的回答不够详细,请编辑您的问题以澄清您想要的结果查询应该是什么样子。这非常重要。如果您不告诉我们您希望查询返回什么,那么您如何期望告诉数据库呢?或者期望我们告诉您如何告诉数据库呢?

1
您的查询非常耗费资源。它会为结果集中的每一行扫描多次数据库。 - PM 77-1
哦,当然。我不确定他们为什么要做他们正在做的子查询。 - Aaron Friel

3
我认为您只需摆脱子查询,其他所有的都会正常工作:
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

我将保留你的工作时间逻辑“不变”。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接