Question

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

The result actually seems to give me Period buckets of days 1-3, days 4-10 and days 11-30. I believe this is because there are overlapping conditions and SQL stops processing the CASE statement as soon as the first condition is met.

What I want are the totals for each bucket (ie 3 day sum, 10 day sum and 30 day sum).

Is there a way to do this without adding additional fields?

PS - the syntax is a bit different then traditional sql because it's vsql (vertica).

Was it helpful?

Solution

If you want to keep this as three rows with one column, here is a way:

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;

EDIT:

The cross join works by creating three rows for each row in the original table. Each of these rows is considered for each group -- so overlaps are not an issue. The groups are defined by their name and the diff value.

In other words, if the data started with one row that was 7 days ago:

ymd                  cost
CURRENT_DATE - 7      $10

Then this gets multiplied into 3 by the cross join:

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

Then, when these are aggregated by which, the correct values are calculated:

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

OTHER TIPS

Make three totals instead of one total, and use the condition to determine where to count each record instead of trying to determine a period for a single total:

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

Note: I'm not sure which date ranges you want to count where, so I made them so that they don't overlap, as that makes most sense if you have using between. If you still want them to overlap then you can just make a comparison instead of using between as any values later than CURRENT_DATE - 1 are already filtered out.

Edit:

To get the result in rows, you can make a union between selects:

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

Try having a different field for each bucket. I'm assuming you want to SUM the cost for each bucket, you may need to change the THEN cost if you want to sum a different field.

You're also missing a WHERE clause in your query. The conditions start with an AND statement, you probably want to correct this.

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

Try to reverse your conditions:

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top