Question

I get crazy because of one query. I have a table like following and I want to get a data - Summa of Values by Status For every Date in interval.

Table

Id    Name    Value    Date        Status
1     pro1    2        01.04.14    0 
2     pro1    8        02.04.14    1 
3     pro2    6        02.04.14    1
4     pro3    0        03.04.14    0
5     pro4    7        03.04.14    0
6     pro4    2        03.04.14    0
7     pro4    4        03.04.14    1
8     pro4    6        04.04.14    1
9     pro4    1        04.04.14    1

For example,

Input: Name = pro4, minDate = 01.02.14, maxDate = 04.09.14

Output:

Date           Values sum for 0 Status          Values sum for 1 Status    
01.04.14       0                                0
02.04.14       0                                0
03.04.14       9   (=7+2)                       4  (only 4 exist)
04.04.14       0                                7  (6+1)

In 01.02.14 and 02.04.14 dates, pro4 has not values by status, but I want to show that rows, because I need all dates in that interval. Can anyone help me to create this query?

Edit:

I can not change structure, I have already that table with data. Every day exist in table many times (minimum 1 time)

Thanks in advance.

Was it helpful?

Solution

Assuming you have a row for each date in the table, use conditional aggregation:

select date,
       sum(Case when name = 'pro4' and status = 0 then Value else 0 end) as values_0,
       sum(case when name = 'pro4' and status = 1 then Value else 0 end) as values_1
from Table t
where date >= '2014-04-01' and date <= '2014-04-09'
group by date
order by date;

If you don't have this list of dates, you can take this approach instead:

with dates as (
      select cast('2014-04-01' as date) as thedate
      union all
      select dateadd(day, 1, thedate)
      from dates
      where thedate < '2014-04-09'
)
select dates.thedate,
       sum(Case when status = 0 then Value else 0 end) as values_0,
       sum(case when status = 1 then Value else 0 end) as values_1
from dates left outer join
     table t
     on t.date = dates.thedate and t.name = 'pro4'
group by dates.thedate;

OTHER TIPS

just an assumption query :

select Distinct date ,case when status = 0 and MAX(date) then SUM(value) ELSE 0 END Status0 ,
case when status = 1 and MAX(date) then SUM(value) ELSE 0 END Status1  from table 

To expand my comment the complete query is

WITH [counter](N) AS
(SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
 SELECT 1)
, days(N) AS (
  SELECT row_number() over (ORDER BY (SELECT NULL)) FROM [counter])
, months (N) AS (
  SELECT N - 1 FROM days WHERE N < 13)
, calendar ([date]) AS (
  SELECT DISTINCT cast(dateadd(DAY, days.n
                     , dateadd(MONTH, months.n, '20131231')) AS date)
  FROM months
       CROSS JOIN days
  )
SELECT a.Name
     , c.Date
     , [Sum of 0] = SUM(CASE Status WHEN 0 THEN Value ELSE 0 END)
     , [Sum of 1] = SUM(CASE Status WHEN 1 THEN Value ELSE 0 END)
FROM   Calendar c
       LEFT  JOIN myTable a ON c.Date = a.Date AND a.name = 'pro4'
WHERE  c.date BETWEEN '20140201' AND '20140904'
GROUP BY c.Date, a.Name
ORDER BY c.Date

Note that the condition on the name need to be in the JOIN, otherwise you'll get only the date of your table.
If you need multiple years just add another CTE for the count and a dateadd(YEAR,...) in the CTE calendar

This is not really the exact query, but I think you can get that by having a query that looks like:

select date, status, sum(value) from table
    where (date between mindate and maxdate) and name = product_name
    group by date, status;

this page gives more info.

EDIT

So the above query only gives a part of the answer required by the OP. A LEFT OUTER JOIN of the original table and the result of the above query on thedate and status fields will give the missing info.

e.g.

select x.date, x.status, x.sum_of_values from table as y 
left outer join 
(select date, status, sum(value) as sum_of_values 
    from table 
    where (date between mindate and maxdate) and name = product_name 
    group by date, status) as x 
on y.date= x.date and y.status = x.status
order by x.date;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top