Wrap Case in Group By statement MySQL - mysql

I am trying to sum up table below into one line with 3Month, 6Month, 9Month, and so on but stuck with mysql error. I did lookup other similar posts and replaced GROUP BY alias with full case but still says contains nonaggregated column. Any help will be greatly appreciated.
mysql> SELECT ith.ItemCode, ith.TransactionDate, DATEDIFF(CURDATE(), ith.TransactionDate) AS Date_Diff,
-> (CASE WHEN DATEDIFF(CURDATE(), ith.TransactionDate) BETWEEN 0 AND 90 THEN ith.TransactionQty ELSE 0 END) AS 0_90_Days,
-> (CASE WHEN DATEDIFF(CURDATE(), ith.TransactionDate) BETWEEN 91 AND 180 THEN ith.TransactionQty ELSE 0 END) AS 91_180_Days,
-> (CASE WHEN DATEDIFF(CURDATE(), ith.TransactionDate) BETWEEN 181 AND 270 THEN ith.TransactionQty ELSE 0 END) AS 181_270_Days,
-> (CASE WHEN DATEDIFF(CURDATE(), ith.TransactionDate) > 270 THEN ith.TransactionQty ELSE 0 END) AS Over_270_Days
->
-> FROM im_itemtransactionhistory ith, ci_item i
-> WHERE ith.TransactionCode = 'PO'
-> AND ith.TransactionDate >= '2018-01-01'
-> AND ith.ItemCode = i.ItemCode
-> AND i.TotalQuantityOnHand > 0
-> AND ith.ItemCode = 512619
-> GROUP BY ith.ItemCode, ith.TransactionDate, ith.TransactionQty
->
-> ORDER BY ith.TransactionDate ASC;
+----------+-----------------+-----------+-----------+-------------+--------------+---------------+
| ItemCode | TransactionDate | Date_Diff | 0_90_Days | 91_180_Days | 181_270_Days | Over_270_Days |
+----------+-----------------+-----------+-----------+-------------+--------------+---------------+
| 512619 | 2018-03-19 | 220 | 0 | 0 | 1200 | 0 |
| 512619 | 2018-05-10 | 168 | 0 | 3600 | 0 | 0 |
| 512619 | 2018-05-11 | 167 | 0 | 600 | 0 | 0 |
| 512619 | 2018-06-15 | 132 | 0 | 3600 | 0 | 0 |
| 512619 | 2018-06-26 | 121 | 0 | 2400 | 0 | 0 |
| 512619 | 2018-07-23 | 94 | 0 | 2400 | 0 | 0 |
| 512619 | 2018-07-26 | 91 | 0 | 1200 | 0 | 0 |
| 512619 | 2018-09-10 | 45 | 1200 | 0 | 0 | 0 |
| 512619 | 2018-09-10 | 45 | 2400 | 0 | 0 | 0 |
| 512619 | 2018-10-16 | 9 | 1092 | 0 | 0 | 0 |
+----------+-----------------+-----------+-----------+-------------+--------------+---------------+
And this is what I've tried..
SELECT ith.ItemCode, ith.TransactionCode, i.TotalQuantityOnHand, DATEDIFF(CURDATE(), ith.TransactionDate),
(CASE WHEN DATEDIFF(CURDATE(), ith.TransactionDate) BETWEEN 0 AND 90 THEN ith.TransactionQty ELSE 0 END) AS 0_90_Days,
(CASE WHEN DATEDIFF(CURDATE(), ith.TransactionDate) BETWEEN 91 AND 180 THEN ith.TransactionQty ELSE 0 END) AS 91_180_Days,
(CASE WHEN DATEDIFF(CURDATE(), ith.TransactionDate) BETWEEN 181 AND 270 THEN ith.TransactionQty ELSE 0 END) AS 181_270_Days,
(CASE WHEN DATEDIFF(CURDATE(), ith.TransactionDate) > 270 THEN ith.TransactionQty ELSE 0 END) AS Over_270_Days,
SUM(CASE WHEN DATEDIFF(CURDATE(), ith.TransactionDate) BETWEEN 0 AND 90 THEN ith.TransactionQty ELSE 0 END) AS 3m_total,
SUM(CASE WHEN DATEDIFF(CURDATE(), ith.TransactionDate) BETWEEN 91 AND 180 THEN ith.TransactionQty ELSE 0 END) AS 6m_total,
SUM(CASE WHEN DATEDIFF(CURDATE(), ith.TransactionDate) BETWEEN 181 AND 270 THEN ith.TransactionQty ELSE 0 END) AS 9m_total,
SUM(CASE WHEN DATEDIFF(CURDATE(), ith.TransactionDate) > 270 THEN ith.TransactionQty ELSE 0 END) AS Over9m_total
FROM im_itemtransactionhistory ith, ci_item i
WHERE ith.TransactionCode = 'PO'
AND ith.TransactionDate >= '2018-01-01'
AND ith.ItemCode = i.ItemCode
AND i.TotalQuantityOnHand > 0
AND ith.ItemCode = 512619
GROUP BY ith.ItemCode,
(CASE WHEN DATEDIFF(CURDATE(), ith.TransactionDate) BETWEEN 0 AND 90 THEN ith.TransactionQty ELSE 0 END),
(CASE WHEN DATEDIFF(CURDATE(), ith.TransactionDate) BETWEEN 91 AND 180 THEN ith.TransactionQty ELSE 0 END),
(CASE WHEN DATEDIFF(CURDATE(), ith.TransactionDate) BETWEEN 181 AND 270 THEN ith.TransactionQty ELSE 0 END),
(CASE WHEN DATEDIFF(CURDATE(), ith.TransactionDate) > 270 THEN ith.TransactionQty ELSE 0 END)
ORDER BY ith.TransactionDate ASC
The error code would return
#1055 - Expression #4 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'mas90.ith.TransactionDate' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
And this is the output I am looking for..
+----------+-----------+-------------+--------------+---------------+
| ItemCode | 0_90_Days | 91_180_Days | 181_270_Days | Over_270_Days |
+----------+-----------+-------------+--------------+---------------+
| 512619 | 4692 | 13800 | 1200 | 0 |
+----------+-----------+-------------+--------------+---------------+

With help from Robert Kock I was able to solve this with query below.
SELECT ith.ItemCode, TEST1.total, TEST2.0_90_Days, TEST3.91_180_Days, TEST4.181_270_Days, TEST5.Over_270_Days
FROM im_itemtransactionhistory ith,
(SELECT ith.ItemCode, SUM(ith.TransactionQty) AS total
FROM im_itemtransactionhistory ith
WHERE ith.TransactionCode = 'PO'
AND ith.ItemCode = 512619
AND ith.TransactionDate >= '2018-01-01'
GROUP BY ith.ItemCode
) AS TEST1,
(SELECT ith.ItemCode, SUM(CASE WHEN DATEDIFF(CURDATE(), ith.TransactionDate) BETWEEN 0 AND 90 THEN ith.TransactionQty ELSE 0 END) AS 0_90_Days
FROM im_itemtransactionhistory ith
WHERE ith.TransactionCode = 'PO'
AND ith.ItemCode = 512619
AND ith.TransactionDate >= '2018-01-01'
GROUP BY ith.ItemCode
) AS TEST2,
(SELECT ith.ItemCode, SUM(CASE WHEN DATEDIFF(CURDATE(), ith.TransactionDate) BETWEEN 91 AND 180 THEN ith.TransactionQty ELSE 0 END) AS 91_180_Days
FROM im_itemtransactionhistory ith
WHERE ith.TransactionCode = 'PO'
AND ith.ItemCode = 512619
AND ith.TransactionDate >= '2018-01-01'
GROUP BY ith.ItemCode
) AS TEST3,
(SELECT ith.ItemCode, SUM(CASE WHEN DATEDIFF(CURDATE(), ith.TransactionDate) BETWEEN 181 AND 270 THEN ith.TransactionQty ELSE 0 END) AS 181_270_Days
FROM im_itemtransactionhistory ith
WHERE ith.TransactionCode = 'PO'
AND ith.ItemCode = 512619
AND ith.TransactionDate >= '2018-01-01'
GROUP BY ith.ItemCode
) AS TEST4,
(SELECT ith.ItemCode, SUM(CASE WHEN DATEDIFF(CURDATE(), ith.TransactionDate) > 270 THEN ith.TransactionQty ELSE 0 END) AS Over_270_Days
FROM im_itemtransactionhistory ith
WHERE ith.TransactionCode = 'PO'
AND ith.ItemCode = 512619
AND ith.TransactionDate >= '2018-01-01'
GROUP BY ith.ItemCode
) AS TEST5
WHERE ith.TransactionCode = 'PO'
AND ith.TransactionDate >= '2018-01-01'
AND ith.ItemCode = 512619
AND ith.ItemCode = TEST1.ItemCode
AND ith.ItemCode = TEST2.ItemCode
GROUP BY ith.ItemCode, TEST2.0_90_Days, TEST3.91_180_Days, TEST4.181_270_Days, TEST5.Over_270_Days
And posting the results hope this helps someone with same problems.
+----------+-------+-----------+-------------+--------------+---------------+
| ItemCode | total | 0_90_Days | 91_180_Days | 181_270_Days | Over_270_Days |
+----------+-------+-----------+-------------+--------------+---------------+
| 512619 | 19692 | 4692 | 13800 | 1200 | 0 |
+----------+-------+-----------+-------------+--------------+---------------+

Related

query to find closest lesser date

I have a table with lunch effective date and its rate.
I need to display rate from its nearest lesser effective date (created_on) for each date column.
lunch_rate table:
created_on | rate
-----------+-------
2018-06-01 | 30
2018-06-04 | 60
Here's what I tried to do:
SELECT userId,
SUM(CASE WHEN date= '2018-06-01' AND lunchStatus = 1 THEN (SELECT MAX(rate) FROM lunch_rate WHERE DATE(created_on) <= date LIMIT 1) ELSE 0 END) '2018-06-01',
SUM(CASE WHEN date= '2018-06-02' AND lunchStatus = 1 THEN (SELECT MAX(rate) FROM lunch_rate WHERE DATE(created_on) <= date LIMIT 1) ELSE 0 END) '2018-06-02',
SUM(CASE WHEN date= '2018-06-03' AND lunchStatus = 1 THEN (SELECT MAX(rate) FROM lunch_rate WHERE DATE(created_on) <= date LIMIT 1) ELSE 0 END) '2018-06-03',
SUM(CASE WHEN date= '2018-06-04' AND lunchStatus = 1 THEN (SELECT MAX(rate) FROM lunch_rate WHERE DATE(created_on) <= date LIMIT 1) ELSE 0 END) '2018-06-04'
FROM
(
SELECT userId, lunchStatus, DATE(issuedDateTime) as date
FROM `lunch_status`
WHERE DATE(issuedDateTime) BETWEEN '2018-06-01' AND '2018-06-04'
) as a
GROUP BY userId;
But this query only gives maximum rate of all, without considering the nearest effective date.
Here's the outcome:
userId | 2018-06-01 | 2018-06-02 | 2018-06-03 | 2018-06-04
------------------------------------------------------------------------
131 | 60 | 60 | 0 | 60
132 | 60 | 60 | 60 | 0
133 | 0 | 0 | 0 | 60
134 | 0 | 0 | 0 | 60
Expected outcome:
userId | 2018-06-01 | 2018-06-02 | 2018-06-03 | 2018-06-04
------------------------------------------------------------------------
131 | 30 | 30 | 0 | 60
132 | 30 | 30 | 30 | 0
133 | 0 | 0 | 0 | 60
134 | 0 | 0 | 0 | 60
SUM(CASE WHEN ... THEN (SELECT MAX(rate) FROM lunch_rate WHERE DATE(created_on) <= date LIMIT 1) ELSE 0 END) ....',
How can I select lunch rate that was effective on that date?
If I understand correctly, you want the calculation in the subquery:
SELECT userId,
SUM(CASE WHEN date = '2018-06-01' AND lunchStatus = 1
THEN rate ELSE 0
END) as `2018-06-01`,
SUM(CASE WHEN date = '2018-06-02' AND lunchStatus = 1
THEN rate ELSE 0
END) as `2018-06-02`,
SUM(CASE WHEN date = '2018-06-03' AND lunchStatus = 1
THEN rate ELSE 0
END) as `2018-06-03`,
SUM(CASE WHEN date = '2018-06-04' AND lunchStatus = 1
THEN rate ELSE 0
END) as `2018-06-04`
FROM (SELECT ls.*, DATE(ls.issuedDateTime) as date
(SELECT lr.rate
FROM lunch_rate lr
WHERE DATE(lr.created_on) <= DATE(ls.issuedDateTime)
ORDER BY lr.created_on DESC
LIMIT 1
) as rate
FROM lunch_status ls
WHERE DATE(issuedDateTime) BETWEEN '2018-06-01' AND '2018-06-04'
) lr
GROUP BY lr.userId;
Note the other changes:
The subquery for lunch_rate does not use MAX(). Instead, it uses ORDER BY.
The column aliases are surrounded by backticks, not single quotes. I don't approve of the names (because they need to be escaped). But if you want them, use proper escape characters.
The tables are given reasonable aliases and column names are qualified.
You could try something like this:
SELECT lr1.rate
FROM lunch_rate lr1
WHERE lr1.created_on <= my_date
AND NOT EXISTS (SELECT *
FROM lunch_rate lr2
WHERE lr2.created_on > lr1.created_on
AND lr2.created_on <= my_date);

Unable to group by to equal values in columns when values are from case statement

This is a view i created
SELECT YEAR(CURRENT_TIMESTAMP) - YEAR(c.date_of_birth) - (RIGHT(CURRENT_TIMESTAMP, 5) < RIGHT(c.date_of_birth, 5)) as age, count(a.id) as occurences, a.celex_id,
COUNT(CASE WHEN c.gender = 'MALE' THEN c.id END) as males,
COUNT(CASE WHEN c.gender = 'FEMALE' THEN c.id END) as females,
COUNT(CASE WHEN c.gender IS NULL THEN c.id END) as unknowns
FROM consumer c, account a
WHERE a.consumer_id = c.id
GROUP BY age, a.celex_id;
This results in:
age | occurences | celex_id | male | female | unknowns
------------------------------------------------------
16 | 1 | 1 | 0 | 1 | 0
65 | 1 | 1 | 1 | 0 | 0
66 | 1 | 1 | 0 | 1 | 0
69 | 1 | 1 | 0 | 0 | 1
And so on.
Now, I have made a query with a case statement, but I am unable to group by the cases, this is the query
SELECT
CASE
WHEN age BETWEEN 0 AND 10 THEN '0-10'
WHEN age BETWEEN 11 AND 20 THEN '11-20'
WHEN age BETWEEN 21 AND 30 THEN '21-30'
WHEN age BETWEEN 31 AND 40 THEN '31-40'
WHEN age BETWEEN 41 AND 50 THEN '41-50'
WHEN age BETWEEN 51 AND 60 THEN '51-60'
WHEN age BETWEEN 61 AND 70 THEN '61-70'
WHEN age BETWEEN 71 AND 80 THEN '71-80'
WHEN age BETWEEN 81 AND 90 THEN '81-90'
WHEN age BETWEEN 91 AND 100 THEN '91-100'
WHEN age > 100 THEN 'Greater than 100'
ELSE 'Unknown'
END AS age_range, males, females, unknowns
FROM age_gender_occurences
WHERE celex_id = 1
GROUP BY age_range, males, females, unknowns
This gives
age_range | males | females | unknowns
--------------------------------------
11-20 | 0 | 1 | 0
21-30 | 0 | 1 | 0
61-70 | 0 | 1 | 0
61-70 | 1 | 0 | 0
61-70 | 0 | 0 | 1
I have tried replicating the case statement directly in the GROUP BY clause, but this does not work. Can someone shed some light over how i can get the age_range to become one-liners? (like 61-70 becoming 1 line instead of 3)
You are missing the aggregation functions. I would write this in terms of the original tables:
SELECT (CASE WHEN age BETWEEN 0 AND 10 THEN '0-10'
WHEN age BETWEEN 11 AND 20 THEN '11-20'
WHEN age BETWEEN 21 AND 30 THEN '21-30'
WHEN age BETWEEN 31 AND 40 THEN '31-40'
WHEN age BETWEEN 41 AND 50 THEN '41-50'
WHEN age BETWEEN 51 AND 60 THEN '51-60'
WHEN age BETWEEN 61 AND 70 THEN '61-70'
WHEN age BETWEEN 71 AND 80 THEN '71-80'
WHEN age BETWEEN 81 AND 90 THEN '81-90'
WHEN age BETWEEN 91 AND 100 THEN '91-100'
WHEN age > 100 THEN 'Greater than 100'
ELSE 'Unknown'
END) AS age_range,
SUM(CASE WHEN c.gender = 'MALE' THEN 1 ELSE 0 END) as males,
SUM(CASE WHEN c.gender = 'FEMALE' THEN 1 ELSE 0 END) as females,
SUM(CASE WHEN c.gender IS NULL THEN 1 ELSE 0 END) as unknowns
FROM consumer c JOIN
account a
ON a.consumer_id = c.id
WHERE celex_id = 1
GROUP BY age_range;
If you want to write it in terms of the view (which seems overkill):
SELECT (CASE WHEN age BETWEEN 0 AND 10 THEN '0-10'
WHEN age BETWEEN 11 AND 20 THEN '11-20'
WHEN age BETWEEN 21 AND 30 THEN '21-30'
WHEN age BETWEEN 31 AND 40 THEN '31-40'
WHEN age BETWEEN 41 AND 50 THEN '41-50'
WHEN age BETWEEN 51 AND 60 THEN '51-60'
WHEN age BETWEEN 61 AND 70 THEN '61-70'
WHEN age BETWEEN 71 AND 80 THEN '71-80'
WHEN age BETWEEN 81 AND 90 THEN '81-90'
WHEN age BETWEEN 91 AND 100 THEN '91-100'
WHEN age > 100 THEN 'Greater than 100'
ELSE 'Unknown'
END) AS age_range,
SUM(males) as males,
SUM(females) as females,
SUM(unknowns) as unknowns
FROM age_gender_occurences
WHERE celex_id = 1
GROUP BY age_range;
In other words, you need to aggregate again. And, in fact, MySQL will do two aggregations in this case, which is why I recommend the simpler version of just using the original tables.

Beginner needs help writing an SQL query of Expenditures by Month, county, and program

I need help writing an SQL query that will yield the following report by program, county, and month.
The table that has this information contains the following columns
I have come up with this query but it will only give me the totals for the month of January. Could some one show me how to get the rest of the months on the report?
Select ServiceCounty, Program, Sum(TotalPaymentTotal) AS January
FROM Table1
WHERE EntryDate BETWEEN '01/01/2014' AND '01/31/2014'
GROUP BY ServiceCounty, Program
ORDER BY ServiceCounty
Thanks in advance for your help!
Try this:
Example:
create table table1 (servicecounty varchar(20), program varchar(20), totalpaymenttotal int, entrydate date);
insert into table1 values
('Mo', 'Program1', 100, '2014-01-01'),('Mo', 'Program1', 100, '2014-03-01'),
('Foo', 'Program1', 100, '2014-02-01'),('Foo', 'Program1', 100, '2014-04-01'),
('Mo', 'Program2', 100, '2014-01-01'),('Mo', 'Program2', 100, '2014-03-01'),
('Foo', 'Program2', 100, '2014-02-01'),('Foo', 'Program2', 100, '2014-04-01');
Query:
select
servicecounty,
program,
sum(case when month(entrydate) = 1 then totalpaymenttotal else 0 end) as January,
sum(case when month(entrydate) = 2 then totalpaymenttotal else 0 end) as February,
sum(case when month(entrydate) = 3 then totalpaymenttotal else 0 end) as March,
sum(case when month(entrydate) = 4 then totalpaymenttotal else 0 end) as April,
sum(case when month(entrydate) = 5 then totalpaymenttotal else 0 end) as May,
sum(case when month(entrydate) = 6 then totalpaymenttotal else 0 end) as June,
sum(case when month(entrydate) = 7 then totalpaymenttotal else 0 end) as July,
sum(case when month(entrydate) = 8 then totalpaymenttotal else 0 end) as August,
sum(case when month(entrydate) = 9 then totalpaymenttotal else 0 end) as September,
sum(case when month(entrydate) = 10 then totalpaymenttotal else 0 end) as October,
sum(case when month(entrydate) = 11 then totalpaymenttotal else 0 end) as November,
sum(case when month(entrydate) = 12 then totalpaymenttotal else 0 end) as December
from table1
where year(entrydate) = 2014 -- gives you data for each month of this year
group by servicecounty, program
Result:
| servicecounty | program | January | February | March | April | May | June | July | August | September | October | November | December |
|---------------|----------|---------|----------|-------|-------|-----|------|------|--------|-----------|---------|----------|----------|
| Foo | Program1 | 0 | 100 | 0 | 100 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| Mo | Program1 | 100 | 0 | 100 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| Foo | Program2 | 0 | 100 | 0 | 100 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| Mo | Program2 | 100 | 0 | 100 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
SQLFiddle example: http://sqlfiddle.com/#!6/d0c80/1
You'll need to add year and month of EntryDate into your group by aggregation.
There are builtin functions in sql server to extract the year & month of a Datetime field like this:
Select ServiceCounty, Program , YEAR(EntryDate) as Year,
MONTH(EntryDate) as Month, Sum(TotalPaymentTotal) AS SumTotal
FROM Table1
GROUP BY YEAR(EntryDate), MONTH(EntryDate), ServiceCounty, Program
ORDER BY ServiceCounty
If you need to group by an arbitrary part of a Datetime, you can use the DATEPART function.
This will get you long formatted data for each month/year. If you really need to get the months into columns, use Sql Server's PIVOT function.

How to do Pivot in MySQL where only one column is the base of the query

I saw a lot of ways on how to do pivot in MySQL but I can't relate it in my situation.
My situation is, I have a column called date_of_mem in tbl_members. I need to count how many member did register in that particular month and year.
For Example:
I have a table called tbl_members with column named id,fname,mname,lname and date_of_mem and so forth.
Now, I want to have this result:
Year | January | February | March | April | May | June | July ...
2013 | 100 | 250 | 50 | 60 | 300 | 280 | 125 ...
2014 | 101 | 240 | 20 | 40 | 200 | 180 | 145 ...
How to do this in MySQL.
Thanks in advance...
select year(date_of_mem) as yr,
sum(case when month(date_of_mem) = 1 then 1 else 0 end) as january,
sum(case when month(date_of_mem) = 2 then 1 else 0 end) as february,
sum(case when month(date_of_mem) = 3 then 1 else 0 end) as march,
sum(case when month(date_of_mem) = 4 then 1 else 0 end) as april,
sum(case when month(date_of_mem) = 5 then 1 else 0 end) as may,
sum(case when month(date_of_mem) = 6 then 1 else 0 end) as june,
sum(case when month(date_of_mem) = 7 then 1 else 0 end) as july,
sum(case when month(date_of_mem) = 8 then 1 else 0 end) as august,
sum(case when month(date_of_mem) = 9 then 1 else 0 end) as september,
sum(case when month(date_of_mem) = 10 then 1 else 0 end) as october,
sum(case when month(date_of_mem) = 11 then 1 else 0 end) as november,
sum(case when month(date_of_mem) = 12 then 1 else 0 end) as december
from tbl_members
group by year(date_of_mem)

Get data from two tables to make an event-calendar

I have two tables
Table Users:
user_id Name
1 John
2 Alice
3 Tom
4 Charles
Table Events:
id event_id start_date end_date user_id
1 1 2013-03-02 2013-03-03 1
2 2 2013-03-02 2013-03-03 3
3 3 2013-03-04 2013-03-04 1
4 2 2013-03-10 2013-03-15 2
I already made the "input" part and is not possible to have two events for the same user in the same day (no overlapping).
I provide the month and the year as variables.
I would like to have a mysql query with results like this:
user_id 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1 0 1 1 3 0 0 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2
3 0 2 2 0 0 0 0 0 0 0 0 0 0 0 0
Thank you!
UPDATED
SELECT user_id,
COALESCE(MIN(CASE WHEN 1 BETWEEN DAY(start_date) AND DAY(end_date) THEN event_id END), 0) `1`,
COALESCE(MIN(CASE WHEN 2 BETWEEN DAY(start_date) AND DAY(end_date) THEN event_id END), 0) `2`,
COALESCE(MIN(CASE WHEN 3 BETWEEN DAY(start_date) AND DAY(end_date) THEN event_id END), 0) `3`,
COALESCE(MIN(CASE WHEN 4 BETWEEN DAY(start_date) AND DAY(end_date) THEN event_id END), 0) `4`,
COALESCE(MIN(CASE WHEN 5 BETWEEN DAY(start_date) AND DAY(end_date) THEN event_id END), 0) `5`,
COALESCE(MIN(CASE WHEN 6 BETWEEN DAY(start_date) AND DAY(end_date) THEN event_id END), 0) `6`,
COALESCE(MIN(CASE WHEN 7 BETWEEN DAY(start_date) AND DAY(end_date) THEN event_id END), 0) `7`,
COALESCE(MIN(CASE WHEN 8 BETWEEN DAY(start_date) AND DAY(end_date) THEN event_id END), 0) `8`,
COALESCE(MIN(CASE WHEN 9 BETWEEN DAY(start_date) AND DAY(end_date) THEN event_id END), 0) `9`,
COALESCE(MIN(CASE WHEN 10 BETWEEN DAY(start_date) AND DAY(end_date) THEN event_id END), 0) `10`,
COALESCE(MIN(CASE WHEN 11 BETWEEN DAY(start_date) AND DAY(end_date) THEN event_id END), 0) `11`,
COALESCE(MIN(CASE WHEN 12 BETWEEN DAY(start_date) AND DAY(end_date) THEN event_id END), 0) `12`,
COALESCE(MIN(CASE WHEN 13 BETWEEN DAY(start_date) AND DAY(end_date) THEN event_id END), 0) `13`,
COALESCE(MIN(CASE WHEN 14 BETWEEN DAY(start_date) AND DAY(end_date) THEN event_id END), 0) `14`,
COALESCE(MIN(CASE WHEN 15 BETWEEN DAY(start_date) AND DAY(end_date) THEN event_id END), 0) `15`
FROM
(
SELECT id, event_id,
CASE WHEN start_date < '2013-03-01' THEN '2013-03-01' ELSE start_date END start_date,
CASE WHEN end_date > '2013-03-31' THEN '2013-03-31' ELSE end_date END end_date,
user_id
FROM events
WHERE (start_date >= '2013-03-01' AND end_date <= '2013-03-31')
OR (start_date < '2013-03-01' AND end_date > '2013-03-31')
OR (start_date < '2013-03-01' AND end_date BETWEEN '2013-03-01' AND '2013-03-31')
OR (start_date BETWEEN '2013-03-01' AND '2013-03-31' AND end_date > '2013-03-31')
) q
GROUP BY user_id
Output:
| USER_ID | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
-----------------------------------------------------------------------------
| 1 | 0 | 1 | 1 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 2 | 2 | 2 | 2 | 2 |
| 3 | 0 | 2 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Here is SQLFiddle demo
I tryed this:
SELECT user_id,
COALESCE(MIN(CASE WHEN '2013-03-01' BETWEEN start_date AND end_date THEN event_id END), 0) `1`,
COALESCE(MIN(CASE WHEN '2013-03-02' BETWEEN start_date AND end_date THEN event_id END), 0) `2`,
COALESCE(MIN(CASE WHEN '2013-03-03' BETWEEN start_date AND end_date THEN event_id END), 0) `3`,
COALESCE(MIN(CASE WHEN '2013-03-04' BETWEEN start_date AND end_date THEN event_id END), 0) `4`,
COALESCE(MIN(CASE WHEN '2013-03-05' BETWEEN start_date AND end_date THEN event_id END), 0) `5`,
COALESCE(MIN(CASE WHEN '2013-03-06' BETWEEN start_date AND end_date THEN event_id END), 0) `6`,
COALESCE(MIN(CASE WHEN '2013-03-07' BETWEEN start_date AND end_date THEN event_id END), 0) `7`,
COALESCE(MIN(CASE WHEN '2013-03-08' BETWEEN start_date AND end_date THEN event_id END), 0) `8`,
COALESCE(MIN(CASE WHEN '2013-03-09' BETWEEN start_date AND end_date THEN event_id END), 0) `9`,
COALESCE(MIN(CASE WHEN '2013-03-10' BETWEEN start_date AND end_date THEN event_id END), 0) `10`,
COALESCE(MIN(CASE WHEN '2013-03-11' BETWEEN start_date AND end_date THEN event_id END), 0) `11`,
COALESCE(MIN(CASE WHEN '2013-03-12' BETWEEN start_date AND end_date THEN event_id END), 0) `12`,
COALESCE(MIN(CASE WHEN '2013-03-13' BETWEEN start_date AND end_date THEN event_id END), 0) `13`,
COALESCE(MIN(CASE WHEN '2013-03-14' BETWEEN start_date AND end_date THEN event_id END), 0) `14`,
COALESCE(MIN(CASE WHEN '2013-03-15' BETWEEN start_date AND end_date THEN event_id END), 0) `15`
FROM events
GROUP BY user_id