【问题标题】:Dealing with overlapping conditions in CASE statement处理 CASE 语句中的重叠条件
【发布时间】:2014-02-27 23:38:08
【问题描述】:
SELECT (CASE WHEN ymd BETWEEN CURRENT_DATE -4 AND CURRENT_DATE -1 THEN '3day total' 
WHEN ymd BETWEEN CURRENT_DATE -11 AND CURRENT_DATE -1 THEN '10day total' 
WHEN ymd BETWEEN CURRENT_DATE -31 AND CURRENT_DATE -1 THEN '30day total' END) AS 'Period',
SUM(cost) cost
FROM table
WHERE ymd BETWEEN CURRENT_DATE -31 AND CURRENT_DATE -1
GROUP BY 1

结果实际上似乎给了我第 1-3 天、第 4-10 天和第 11-30 天的时段。我相信这是因为存在重叠的条件,一旦满足第一个条件,SQL 就会停止处理 CASE 语句。

我想要的是每个桶的总数(即 3 天总和、10 天总和和 30 天总和)。

有没有办法在不添加额外字段的情况下做到这一点?

PS - 语法与传统 sql 有点不同,因为它是 vsql (vertica)。

【问题讨论】:

  • vsql 一个用于基于 Unix 的系统的前端实用程序,提供元命令和各种类似 shell 的功能,便于编写 SQL
  • 我不知道 Vertica 是如何处理日期/时间/时间戳类型的,但您一般don't want to use BETWEEN with them。将时间戳(和一般的时间)视为自然数序列 - 在精确整数之前没有“最后一个”值(小数秒在概念上是无限的)。

标签: sql vertica vsql


【解决方案1】:

制作三个总计而不是一个总计,并使用条件来确定对每条记录进行计数的位置,而不是尝试确定单个总计的期间:

select
  sum(case when ymd between CURRENT_DATE - 4 and CURRENT_DATE - 1 then cost else 0 end) as '3day total',
  sum(case when ymd BETWEEN CURRENT_DATE - 11 and CURRENT_DATE - 5 then cost else 0 end) as '10day total',
  sum(case when ymd BETWEEN CURRENT_DATE - 31 and CURRENT_DATE - 12 then cost else 0 end) as '30day total'
from
  table
and
  ymd between CURRENT_DATE -31 and CURRENT_DATE -1
group by
  1

注意:我不确定您想在哪里计算哪些日期范围,所以我制作了它们以便它们不会重叠,因为如果您使用 between,这最有意义。如果您仍然希望它们重叠,那么您可以进行比较,而不是使用 between,因为任何晚于 CURRENT_DATE - 1 的值都已被过滤掉。

编辑:

要获得行中的结果,您可以在选择之间进行联合:

select '3day total' as period, sum(cost) as cost
from table
where ymd between CURRENT_DATE - 4 and CURRENT_DATE - 1
union all
select '10day total', sum(cost)
from table
where ymd BETWEEN CURRENT_DATE - 11 and CURRENT_DATE - 5
union all
select '30day total', sum(cost)
from table
where ymd BETWEEN CURRENT_DATE - 31 and CURRENT_DATE - 12

【讨论】:

  • 我刚刚注意到他在原始 SQL 中遗漏了 WHERE 子句。我改变了我的答案,你可能也想在你的答案中更正它。
  • 我认为group by 1 是不必要的
  • 是的,但它在 OP 的原始查询中。
  • 原始查询不同。它有一个 periodsum 列。按时期分组。你按什么分组?
  • @steinmas:我不知道 vsql 和 SQL 之间有什么不同,我认为缺少的 where 就是其中之一。如果不是,那么 OP 应该能够从实际查询中使用该部分。
【解决方案2】:

如果你想保持三行一列,这里有一种方法:

SELECT which,
       sum(CASE WHEN ymd BETWEEN CURRENT_DATE - diff AND CURRENT_DATE -1 THEN cost
                else 0
           end) as cost
FROM table t cross join
     (select '3day total' as which, 4 as diff union all
      select '10day total', 11 union all
      select '30day total', 31
     ) w
WHERE ymd BETWEEN CURRENT_DATE -31 AND CURRENT_DATE -1
GROUP BY which;

编辑:

cross join 的工作原理是为原始表中的每一行创建三行。每个组都考虑这些行中的每一行——因此重叠不是问题。这些组由它们的名称和diff 值定义。

换句话说,如果数据以 7 天前的一行开始:

ymd                  cost
CURRENT_DATE - 7      $10

然后将 cross join 乘以 3:

which         diff       ymd                 cost
3day total      4        CURRENT_DATE - 7     $10
10day total    11        CURRENT_DATE - 7     $10
30day total    31        CURRENT_DATE - 7     $10

然后,当这些由which 聚合时,会计算出正确的值:

which         Total
3day total      $0
10day total    $10
30day total    $10

【讨论】:

  • 我在每个期间的成本列中得到 0 结果。有什么想法吗?
  • @ChrisArmstrong 。 . .呸! CURRENT_DATE - diff 类似于CURRENT_DATE - (-4),即CURRENT_DATE + 4。哎呀。符号错误。
【解决方案3】:

尝试为每个存储桶设置不同的字段。我假设您想对每个存储桶的成本求和,如果您想对不同的字段求和,您可能需要更改 THEN cost

您的查询中还缺少WHERE 子句。条件以AND 语句开头,您可能需要更正此问题。

SELECT SUM(CASE WHEN ymd BETWEEN CURRENT_DATE -4 AND CURRENT_DATE -1 THEN cost ELSE 0 END) as '3day total',
SUM(CASE WHEN ymd BETWEEN CURRENT_DATE -11 AND CURRENT_DATE -1 THEN cost ELSE 0 END) as '10day total', 
SUM(CASE WHEN ymd BETWEEN CURRENT_DATE -31 AND CURRENT_DATE -1 THEN cost ELSE 0 END) as  '30day total' END) AS 'Period'
FROM table
WHERE ymd BETWEEN CURRENT_DATE -31 AND CURRENT_DATE -1
GROUP BY 1

【讨论】:

  • 同样适用于您:您的答案中不需要 GROUP BY 1
【解决方案4】:

尝试扭转你的条件:

SELECT (CASE WHEN ymd BETWEEN CURRENT_DATE -31 AND CURRENT_DATE -1 THEN '30day total' 
WHEN ymd BETWEEN CURRENT_DATE -11 AND CURRENT_DATE -1 THEN '10day total' 
WHEN ymd BETWEEN CURRENT_DATE -4 AND CURRENT_DATE -1 THEN '3day total' 
END) AS 'Period',
SUM(cost) cost
FROM table
WHERE ymd BETWEEN CURRENT_DATE -31 AND CURRENT_DATE -1
GROUP BY 1

【讨论】:

  • 这具有在 30 天期间内将所有成本存储起来的预期效果。
猜你喜欢
  • 1970-01-01
  • 2017-02-20
  • 2012-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多