【问题标题】:Case statement is ignoring where clausecase 语句忽略 where 子句
【发布时间】:2018-01-15 22:51:58
【问题描述】:

我正在尝试创建一个返回多个计数的 SQL 语句。下面的计数按我的预期工作,但 case 语句忽略了我的查询的 where 子句。

我正在尝试获取满足 where 条件的 PacketId 的总数。然后获得第二个总数,显示满足 where 条件且 StatusId 为 3 的 PacketId 的总和。

*edit Table1 和 Table2 共享 PacketId 作为外键。

Select 
Count(Distinct wpq.PacketId) AS Total,
SUM(Case When wpq.StatusId = 3 THEN 1 ELSE 0 END) as OtherCount
FROM [Table1] ppo JOIN [Table2] wpq ON ppo.PacketId = wpq.PacketId
WHERE wpq.CreateDate between  '11/1/2017' and '1/1/2018' and ppo.IsSelected = 1

【问题讨论】:

  • 您是否有数据样本以及当前返回的内容?这可能有助于弄清楚为什么 case 语句没有返回你想要的。
  • 您是在寻找唯一StatusIDs 的数量还是总数?关于 CASE 语句的语法没有什么不正确的,所以你的逻辑有问题。此外,您在 WHERE 子句中隐式转换为日期。请使用正确的格式模型明确执行此操作以避免错误。最后,这是 SQL Server 吗?
  • 您的查询看起来像 T-SQL,但您应该始终在标签中指明 dbms 类型。 sql 本身通常是不够的。 +fyi:正确的术语是 case expression(不是 case 语句),因为它们评估为单个值。
  • 正确标记!!!这是哪个dbms????
  • 如果是 SQL Server,则添加 SQL Server 标签。如果有人让你查询错误的 dbms,那就没用了。

标签: sql sql-server tsql case-when


【解决方案1】:

我怀疑您获得的othercount 的数字可能比预期的要高,但这可能是由于使用了count(distinct...),这会减少第一列的结果,但不会减少第二列的结果。或许引入子查询来仅选择不同的值会有所帮助?

SELECT DISTINCT
      wpq.PacketId
    , wpq.StatusId
FROM [Table1] ppo
JOIN [Table2] wpq ON ppo.PacketId = wpq.PacketId
WHERE wpq.CreateDate BETWEEN '11/1/2017' AND '1/1/2018'
AND ppo.IsSelected = 1
;

然后从那开始计算,例如:

SELECT
      COUNT(PacketId)                                 AS total
    , COUNT(CASE WHEN StatusId = 3 THEN StatusId END) AS othercount
    , SUM(CASE WHEN StatusId = 3 THEN 1 ELSE 0 END)   AS othersum
FROM (
      SELECT DISTINCT
            wpq.PacketId
          , wpq.StatusId
      FROM [Table1] ppo
      JOIN [Table2] wpq ON ppo.PacketId = wpq.PacketId
      WHERE wpq.CreateDate BETWEEN '11/1/2017' AND '1/1/2018'
      AND ppo.IsSelected = 1
      ) AS d
;

注意:COUNT() 函数忽略空值,所以我添加了另一种计算方法来考虑。我更喜欢在这样的查询中使用COUNT()

我还想指出,您使用看似 M/D/YYYY 日期文字的内容并不安全。 T-SQL 中最安全的日期文字格式是 YYYYMMDD。同样,使用 between 不是日期范围的最佳做法,wpuld 鼓励您改用 >=<,如下所示:

SELECT
      COUNT(PacketId)                                 AS total
    , COUNT(CASE WHEN StatusId = 3 THEN StatusId END) AS othercount
    , SUM(CASE WHEN StatusId = 3 THEN 1 ELSE 0 END)   AS othersum
FROM (
      SELECT DISTINCT
            wpq.PacketId
          , wpq.StatusId
      FROM [Table1] ppo
      JOIN [Table2] wpq ON ppo.PacketId = wpq.PacketId
      WHERE wpq.CreateDate >= '20171101' AND wpq.CreateDate < '20180101'
      AND ppo.IsSelected = 1
      ) AS d
;

请注意,我不确定您是否确实要包含 2018 年 1 月 1 日,如果您愿意,请改用 &lt; '20180102'

【讨论】:

  • 谢谢!这非常有效!度过一个愉快的夜晚。
  • 太好了,很高兴知道。你“接受”一个正确的答案对其他人是有帮助的。你知道怎么做吗?
  • 当然,我接受了。 (我试图将其投票为有用,但在我的声誉达到 15 之前不允许这样做)
  • :) 谢谢。通过接受,您将获得 2 分,以帮助您获得超过 15 个代表点。 (也许您在过去的问题中没有这样做过?
【解决方案2】:

我建议您使用标准日期格式。大多数数据库都支持 YYYY-MM-DD:

SELECT COUNT(DISTINCT wpq.PacketId) AS Total,
       SUM(Case When wpq.StatusId = 3 THEN 1 ELSE 0 END) as OtherCount
FROM [Table1] ppo JOIN
     [Table2] wpq
     ON ppo.PacketId = wpq.PacketId
WHERE wpq.CreateDate >= '2017-11-01' AND
      wpq.CreateDate <= '2018-01-01' AND
      ppo.IsSelected = 1;

日期比较可能确实是作为字符串进行的,因此它们没有达到您的预期。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-31
    • 2014-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-26
    • 2017-04-01
    相关资源
    最近更新 更多