I have two tables. In TableNames the library of several songs is stored. In TableTimes the exact date and time on which the song will be played is stored.
In every new week I'm checking if there are new songs which were never played before. Easy. But my problem is the following: I need to know if a song will be played before or after 12:00:00 (24h). Therefore I'm running a CASE WHEN and output an alias TimeCase with value + or -, please see query below.
My query should output if there are songs in the actual week which has a new "TimeCase". You can find an example below with ID 101.
ID 101 is not new in Week 201908 but it plays the first time after 12:00:00 and therefore needs to be in my query output.
TableNames
+-------+-----+
| Name | id |
+-------+-----+
| Song1 | 100 |
+-------+-----+
| Song2 | 101 |
+-------+-----+
| Song3 | 102 |
+-------+-----+
| Song4 | 103 |
TableTimes:
+--------+--------+------+
| Week | Time | idFI |
+--------+--------+------+
| 201908 | 08:00 | 100 |
+--------+--------+------+
| 201908 | 19:00 | 101 |
+--------+--------+------+
| 201907 | 09:00 | 101 |
+--------+--------+------+
| 201906 | 22:00 | 103 |
My Query:
SELECT t2.idFI, t1.id, Name, TimeCase
FROM TableTimes t2
JOIN TableNames t1 ON t2.idFI = t1.id
JOIN (
SELECT idFI,
CASE WHEN Time < '12:00:00' THEN '-'
ELSE '+'
END AS TimeCase
FROM TableTimes GROUP BY idFI, TimeCase
) t3 ON t2.idFI = t3.idFI
WHERE '201908' = Week
AND deleteSZ = false
AND NOT EXISTS
(
SELECT null
FROM TableTimes t5
JOIN (
SELECT idFI,
CASE WHEN Time < '12:00:00' THEN '-'
ELSE '+'
END AS TimeCaseBefore
FROM TableTimes GROUP BY idFI, TimeCaseBefore
) t4 ON t5.idFI = t4.idFI
WHERE t5.idFI = t2.idFI
AND TimeCaseBefore = TimeCase
AND Week<'201908'
AND deleteSZ = false
GROUP BY t5.idFI, TimeCaseBefore)
GROUP BY TimeCase, t2.idFI
Which is giving me the following:
+-------+-----+------+----------+
| Name | id | idFI | TimeCase |
+-------+-----+------+----------+
| Song1 | 100 | 100 | - |
+-------+-----+------+----------+
What I actually want is:
+-------+-----+------+----------+
| Name | id | idFI | TimeCase |
+-------+-----+------+----------+
| Song1 | 100 | 100 | - |
+-------+-----+------+----------+
| Song2 | 101 | 101 | + |
+-------+-----+------+----------+
My understanding of my problem is, that I should be able to change t5.idFI = t2.idFI to t5.TimeCaseBefore = t2.TimeCase which is not possible due to the alias.
How can I solve this?
Final solutions based on P.Salmon:
select tn.name,
idfi,
case when thiswkafter12 > 0 and priorwkafter12 = 0 and thiswkbefore12 > 0 and priorwkbefore12 = 0 then '+ -'
when thiswkafter12 > 0 and priorwkafter12 = 0 and priorwkbefore12 = 0 then '+'
when thiswkbefore12 > 0 and priorwkbefore12 = 0 and priorwkafter12 = 0 then '-'
end as timecase
from
(
SELECT idfi,
sum(case when week = 201908 and time >= '12:00:00' then 1 else 0 end) as thiswkafter12,
sum(case when week = 201908 and time < '12:00:00' then 1 else 0 end) as thiswkbefore12,
sum(case when week < 201908 and time >= '12:00:00' then 1 else 0 end) as priorwkafter12,
sum(case when week < 201908 and time < '12:00:00' then 1 else 0 end) as priorwkbefore12
FROM TABLETIMES
group by idfi
having (thiswkafter12 > 0 and priorwkafter12 = 0 and thiswkbefore12 > 0 and priorwkbefore12 = 0) or
(thiswkafter12 > 0 and priorwkafter12 = 0 and priorwkbefore12 = 0) or
(thiswkbefore12 > 0 and priorwkbefore12 = 0 and priorwkafter12 = 0)
) s
join tablenames tn on tn.id = s.idfi ;
Maybe a simpler approach working out how often a song has been played this week and comparing to how often played in previous weeks, split into am and pm. I assume that the inverse of your example for 101 can also apply ie a case where a song has been played in the am this week but was played in the pm previously.
Note I have added a song played for the first time in the am AND pm this week
+--------+----------+------+
| Week | Time | idFI |
+--------+----------+------+
| 201908 | 08:00:00 | 100 |
| 201908 | 19:00:00 | 101 |
| 201907 | 09:00:00 | 101 |
| 201906 | 22:00:00 | 103 |
| 201908 | 08:00:00 | 104 |
| 201908 | 13:00:00 | 104 |
| 201908 | 08:00:00 | 104 |
| 201908 | 13:00:00 | 104 |
+--------+----------+------+
8 rows in set (0.00 sec)
select tn.name,
idfi,
case when thiswkafter12 > 0 and priorwkafter12 = 0 then '+'
when thiswkbefore12 > 0 and priorwkbefore12 = 0 then '-'
end as timecase
from
(
SELECT idfi,
sum(case when week = 201908 and time >= '12:00:00' then 1 else 0 end) as thiswkafter12,
sum(case when week = 201908 and time < '12:00:00' then 1 else 0 end) as thiswkbefore12,
sum(case when week < 201908 and time >= '12:00:00' then 1 else 0 end) as priorwkafter12,
sum(case when week < 201908 and time < '12:00:00' then 1 else 0 end) as priorwkbefore12
FROM TABLETIMES
group by idfi
having (thiswkafter12 > 0 and priorwkafter12 = 0) or
(thiswkbefore12 > 0 and priorwkbefore12 = 0)
) s
join tablenames tn on tn.id = s.idfi ;
+-------+------+----------+
| name | idfi | timecase |
+-------+------+----------+
| Song1 | 100 | - |
| Song2 | 101 | + |
| song5 | 104 | + |
+-------+------+----------+
3 rows in set (0.00 sec)
You haven't said what should happen in the case of 104 so I'm assumming pm wins.
Related
I have two tables: Here is the
sqlfiddle (http://sqlfiddle.com/#!9/5a51734/5)
1) [table:data_aoc]
| aoc_id | aoc_name | aoc_type | client_id |
|------------------------------|-----------|
1 | MA01 | sensor_1 | 4 | 1 |
2 | MA02 | sensor_2 | 15 | 1 |
2) table:data_log
| log_id | log_aoc_id | trans_type | trans_value | trans_date |
|-------------------------------------------------------------|
1 | x1a1 | MA01 | 0 | 90 | 2017-10-20 |
2 | afaf | MA01 | 0 | 90 | 2017-10-21 |
3 | va12 | MA02 | 0 | 10 | 2017-10-21 |
4 | gag2 | MA02 | 0 | 10 | 2017-11-25 |
Expected Result
Total value for MA02 should be 10 but it shows 20
my queries as follows
SELECT
(CASE
WHEN a.aoc_type IN ('4')
THEN IFNULL((SUM(b.trans_value * case b.trans_type when '0' then -1 else 1 end)),0)
WHEN a.aoc_type IN ('15')
THEN IFNULL((SUM(b.trans_value * case when b.trans_type='0' AND DATE(b.trans_date) <= DATE(NOW()) then -1 else 1 end)),0)
END) as total
FROM data_aoc a
LEFT JOIN data_log b ON b.log_aoc_id = a.aoc_id
WHERE a.client_id='1'
GROUP BY a.aoc_name
ORDER BY a.aoc_id asc
Iam expecting when aoc_type is (15) it will sum the value within the date condition
DATE(b.trans_date) <= DATE(NOW())
but when i execute the queries, it produce result not within the date condition. *some timestamps are generated in advance beyond the NOW() date time.
The desired result should be:
| Total |
|-------|
| -180 |
| 10 |
But i get
| Total |
|-------|
| -180 |
| 0 | <----- it should be 10 because of the date condition i put
thank you!
As a follow-up of same findings from Don, And your clarification of don't count after, I came up with this query... Pre-check on the date first and if after, multiply by zero, OTHERWISE, apply the +/- 1 factor.
SELECT
SUM( b.trans_value *
CASE when ( a.aoc_type = '15'
AND b.trans_type = '0'
AND DATE(b.trans_date) > DATE(NOW()) )
then 0
when ( a.aoc_type = '4'
AND b.trans_type = '0' )
OR ( a.aoc_type = '15'
AND b.trans_type = '0'
AND DATE(b.trans_date) <= DATE(NOW()) )
then -1 else 1 end ) as total
FROM
data_aoc a
LEFT JOIN data_log b
ON a.aoc_id = b.log_aoc_id
WHERE
a.client_id='1'
GROUP BY
a.aoc_name
ORDER BY
a.aoc_id asc
Also posted on SQL Fiddle
It seems to be working exactly as it should.
With the date clause I get:
Sensor 1 = -180
Sensor 2 = 0
If you break down the summing you get two rows to be summed for sensor #2
10 on 10-21 (before the date restriction so it's multiplied by -1)
and
10 on 11-25 (after the date restriction so it's multiplied by 1)
10 * -1 + 10 * 1 = 0
The sensor #2 reading is correctly 0.
I do not understand why you think it should be anything else.
I have this database:
| id | name | email | control_number | created | | | | | |
|:--:|-------|-----------------|----------------|------------|---|---|---|---|---|
| 1 | john | john#gmail.com | 1 | 14/09/2016 | | | | | |
| 2 | carl | carl#gmail.com | 1 | 13/08/2016 | | | | | |
| 3 | frank | frank#gmail.com | 2 | 12/08/2016 | | | | | |
And i want to get the COUNT in the last 12 months by the control_number.
basicly is a COUNT where control_number = 1 but by month.
So if the query is done today, its september, it should start from september to October 2015 and display the count of records for each month.
Result should be:
09/2016 = 50
08/2016 = 35
07/2016 = 20
06/2016 = 50
05/2016 = 21
04/2016 = 33
03/2016 = 60
02/2016 = 36
01/2016 = 11
12/2015 = 0
11/2015 = 0
10/2015 = 0
Hmmm. Getting the 0 values can be tricky. Assuming that you have some data each month (even if not for "1"), th en you can do:
select extract(year_month from created) as yyyymm,
sum(control_number = 1)
from t
where created >= date_sub(curdate(), interval 12 month)
group by extract(year_month from created)
order by yyyymm;
If you don't have at least one record for each month, then you'll need a left join and a table with one row per month.
Try this:
select CONCAT(SUBSTRING(ym, 5, 2), '/', SUBSTRING(ym, 1, 4)) Month, Count from (
select EXTRACT(YEAR_MONTH FROM created) ym, count(*) Count
from mytable
where EXTRACT(YEAR_MONTH FROM created) > (EXTRACT(YEAR_MONTH FROM SUBDATE(NOW(), INTERVAL 1 YEAR))
group by 1
order by 1 desc) x
Try:
select concat(month(created),'/',year(created)) as period, count(*) as cnt
from mytable
where control_number=1 and TIMESTAMPDIFF(year, created, now())=0
group by (month(created));
I'm trying create an SQL query to resolve my problem.
My Table:
+----+---------------------+-------+
| id | date | value |
+----+---------------------+-------+
| 1 | 2014-10-10 05:10:10 | 10 |
+----+---------------------+-------+
| 2 | 2014-10-10 09:10:10 | 20 |
+----+---------------------+-------+
| 3 | 2014-10-10 15:10:10 | 30 |
+----+---------------------+-------+
| 4 | 2014-10-10 23:10:10 | 40 |
+----+---------------------+-------+
| 5 | 2014-10-11 08:10:10 | 15 |
+----+---------------------+-------+
| 6 | 2014-10-11 09:10:10 | 25 |
+----+---------------------+-------+
| 7 | 2014-10-11 10:10:10 | 30 |
+----+---------------------+-------+
| 8 | 2014-10-11 23:10:10 | 40 |
+----+---------------------+-------+
I want to sum value in groups by days and this days in three sub groups like a 'morning'(06:00 - 12:00), 'afternoon'(12:00 - 18:00) and 'night'(00:00 - 06:00 and 18:00 - 24:00).
something like this:
+------------+-------+---------+-----------+-------+
| date | value | morning | afternoon | night |
+------------+-------+---------+-----------+-------+
| 2014-10-10 | 100 | 20 | 30 | 50 |
+------------+-------+---------+-----------+-------+
| 2014-10-11 | 110 | 70 | 0 | 40 |
+------------+-------+---------+-----------+-------+
You could use a couple of sums over case expressions:
SELECT DAY(`date`) AS `date`
SUM(CASE WHEN HOUR(`date`) BETWEEN 6 AND 12 THEN value ELSE 0 END) AS `morning`,
SUM(CASE WHEN HOUR(`date`) BETWEEN 12 AND 18 THEN value ELSE 0 END) AS `afternoon`,
SUM(CASE WHEN HOUR(`date`) < 6 OR HOUR(`date`) > 18 THEN value ELSE 0 END) AS `evening`
FROM my_table
GROUP BY DAY(`date`)
There are multiple ways to go about this, but for myself I'd do it by first extracting the pseudo information in a CROSS APPLY, and then grouping on this information.
I believe this offers significant readibility benefits, and allows you to re-use any calculations in other clauses. For example, you have centralised the grouping mechanism, meaning that you only need to change it in the one place rather than in the select and the group by. Similarly, you could add "extraData.Morning = 1" to a WHERE clause rather than re-writing the calculation for mornings.
For example:
CREATE TABLE #TestData (ID INT, Data DATETIME, Value INT)
INSERT INTO #TestData (ID, Data, Value) VALUES
(1 ,'2014-10-10 05:10:10' ,10)
,(2 ,'2014-10-10 09:10:10' ,20)
,(3 ,'2014-10-10 15:10:10' ,30)
,(4 ,'2014-10-10 23:10:10' ,40)
,(5 ,'2014-10-11 08:10:10' ,15)
,(6 ,'2014-10-11 09:10:10' ,25)
,(7 ,'2014-10-11 10:10:10' ,30)
,(8 ,'2014-10-11 23:10:10' ,40)
SELECT
extraData.DayComponent
,SUM(td.Value)
,SUM(CASE WHEN extraData.Morning = 1 THEN td.Value ELSE 0 END) AS Morning
,SUM(CASE WHEN extraData.Afternoon = 1 THEN td.Value ELSE 0 END) AS Afternoon
,SUM(CASE WHEN extraData.Night = 1 THEN td.Value ELSE 0 END) AS Night
FROM #TestData td
CROSS APPLY (
SELECT
DATEADD(dd, 0, DATEDIFF(dd, 0, td.Data)) AS DayComponent
,CASE WHEN DATEPART(HOUR, td.Data) BETWEEN 6 AND 12 THEN 1 ELSE 0 END AS Morning
,CASE WHEN DATEPART(HOUR, td.Data) BETWEEN 12 AND 18 THEN 1 ELSE 0 END AS Afternoon
,CASE WHEN DATEPART(HOUR, td.Data) BETWEEN 0 AND 6
OR DATEPART(HOUR, td.Data) BETWEEN 18 AND 24 THEN 1 ELSE 0 END AS Night
) extraData
GROUP BY
extraData.DayComponent
DROP TABLE #TestData
I'm using two tables in the database.
The first contains data related to the successful and unsuccessful payments while the second table contains data regarding the status of services.
The result of the query should combine both tables and as a result list the successful and unsuccessful payments grouped by the days as well as the status of services grouped by days.
First table looks like:
id | charged | date
-----------------------------
8 | OK | 2011-12-03
7 | OK | 2011-12-03
9 | NO | 2011-12-03
11 | OK | 2011-12-04
14 | NO | 2011-12-04
The second table looks like:
id | status | date
--------------------------
8 | 1 | 2011-12-03
9 | 1 | 2011-12-03
11 | 0 | 2011-12-04
12 | 0 | 2011-12-04
14 | 1 | 2011-12-04
The correct query result should be:
date | not_charged | charged | status_1 | status_0
-----------------------------------------------------------
2011-12-04 | 1 | 1 | 1 | 2
2011-12-03 | 1 | 2 | 2 | 0
The query that I've tried looks like this:
SELECT i.date, SUM(
CASE WHEN i.charged = 'NO'
THEN 1 ELSE 0 END ) AS not_charged, SUM(
CASE WHEN i.charged = 'OK'
THEN 1 ELSE 0 END ) AS charged, SUM(
CASE WHEN s.status = '1'
THEN 1 ELSE 0 END ) AS status_1, SUM(
CASE WHEN s.status = '0' THEN 1 ELSE 0 END ) AS status_0
FROM charge i INNER JOIN status s ON s.date = i.date
GROUP BY i.date
But I get the wrong result that looks like this
date | not_charged | charged | status_1 | status_0
---------------------------------------------------------
2011-12-04 | 3 | 3 | 2 | 4
2011-12-03 | 2 | 4 | 6 | 0
What I'm doing wrong and how can I get the correct result?
Thanks for all suggestions.
Try this one -
SELECT date,
SUM(IF(charged = 'NO', 1, 0)) not_charged,
SUM(IF(charged = 'OK', 1, 0)) charged,
SUM(IF(status = 1, 1, 0)) status_1,
SUM(IF(status = 0, 1, 0)) status_0
FROM (
SELECT date, charged, NULL status FROM charge
UNION ALL
SELECT date, NULL charged, status FROM status
) t
GROUP BY date DESC;
+------------+-------------+---------+----------+----------+
| date | not_charged | charged | status_1 | status_0 |
+------------+-------------+---------+----------+----------+
| 2011-12-04 | 1 | 1 | 1 | 2 |
| 2011-12-03 | 1 | 2 | 2 | 0 |
+------------+-------------+---------+----------+----------+
This assumes the ID columns related that service status and payment status together...
SELECT
COALESCE(charge.date, status.date) AS date,
SUM(CASE WHEN charge.charged = 'NO' THEN 1 ELSE 0 END) AS not_charged,
SUM(CASE WHEN charge.charged = 'OK' THEN 1 ELSE 0 END) AS charged,
SUM(CASE WHEN status.status = '0' THEN 1 ELSE 0 END) AS status_0,
SUM(CASE WHEN status.status = '1' THEN 1 ELSE 0 END) AS status_1
FROM
charge
FULL OUTER JOIN
status
ON charge.id = status.id
GROUP BY
COALESCE(charge.date, status.date)
Note, I'm note sure how you want to deal with 7 (No status record) and 12 (no charge record). This currently just counts what is there.
Alternatively, if you don't want to related the records by ID, you can still relate by date but you need to change your logic.
At present you're getting this, because you only relate by date...
id | charged | date id | status | date
----------------------------- --------------------------
8 | OK | 2011-12-03 8 | 1 | 2011-12-03
8 | OK | 2011-12-03 9 | 1 | 2011-12-03
7 | OK | 2011-12-03 8 | 1 | 2011-12-03
7 | OK | 2011-12-03 9 | 1 | 2011-12-03
9 | NO | 2011-12-03 8 | 1 | 2011-12-03
9 | NO | 2011-12-03 9 | 1 | 2011-12-03
11 | OK | 2011-12-04 11 | 0 | 2011-12-04
11 | OK | 2011-12-04 12 | 0 | 2011-12-04
11 | OK | 2011-12-04 14 | 1 | 2011-12-04
14 | NO | 2011-12-04 11 | 0 | 2011-12-04
14 | NO | 2011-12-04 12 | 0 | 2011-12-04
14 | NO | 2011-12-04 14 | 1 | 2011-12-04
Instead you need to consolidate the data down to 1 per date per table, then join...
SELECT
COALESCE(charge.date, status.date) AS date,
charge.not_charged,
charge.charged,
status.status_0,
status.status_1
FROM
(
SELECT
date,
SUM(CASE WHEN charged = 'NO' THEN 1 ELSE 0 END) AS not_charged,
SUM(CASE WHEN charged = 'OK' THEN 1 ELSE 0 END) AS charged
FROM
charge
GROUP BY
date
)
AS charge
FULL OUTER JOIN
(
SELECT
date,
SUM(CASE WHEN charged = '0' THEN 1 ELSE 0 END) AS status_0,
SUM(CASE WHEN charged = '1' THEN 0 ELSE 1 END) AS status_1
FROM
status
GROUP BY
date
)
AS status
ON charge.date = status.date
There are other methods, but hopefully this explains a bit for you.
I suggest using a UNION ALL:
select date,
coalesce(sum(not_charged),0) not_charged,
coalesce(sum(charged),0) charged,
coalesce(sum(status_1),0) status_1,
coalesce(sum(status_0),0) status_0
from (select date,
case charged when 'NO' then 1 end not_charged,
case charged when 'OK' then 1 end charged,
0 status_1,
0 status_0
from charge
union all
select date,
0 not_charged,
0 charged,
case status when '1' then 1 end status_1,
case status when '0' then 1 end status_0
from status) sq
group by date
On a previous question a table could be created and populated with the days of the month, but I'd like that table to be populated slightly different: each day of the month should have three different hour intervals.
According to that question, this code by Tom Mac:
create table all_date
(id int unsigned not null primary key auto_increment,
a_date date not null,
last_modified timestamp not null default current_timestamp on update current_timestamp,
unique key `all_date_uidx1` (a_date));
And then,
DELIMITER //
CREATE PROCEDURE populate_all_dates(IN from_date DATE, IN days_into_future INT)
BEGIN
DECLARE v_date DATE;
DECLARE ix int;
SET ix := 0;
SET v_date := from_date;
WHILE v_date <= (from_date + interval days_into_future day) DO
insert into all_date (a_date) values (v_date)
on duplicate key update last_modified = now();
set ix := ix +1;
set v_date := from_date + interval ix day;
END WHILE;
END//
DELIMITER ;
And then you can run:
call populate_all_dates('2011-10-01',30);
To populate all dates for October (or whatever month, change the values of the function)
With that I could run the following query
select day(a.a_date) as 'October',
IFNULL(t.a1,0) as 'Auth1',
IFNULL(t.a2,0) as 'Auth2',
IFNULL(t.a50,0) as 'Auth50'
from all_date a
LEFT OUTER JOIN
(
SELECT date(wp.post_date) as post_date,
sum(case when wp.post_author = '1' then 1 else 0 end) as a1,
sum(case when wp.post_author = '2' then 1 else 0 end) as a2,
sum(case when wp.post_author = '50' then 1 else 0 end) as a50,
count(*) as 'All Auths'
FROM wp_posts wp
WHERE wp.post_type = 'post'
AND wp.post_date between '2011-10-01' and '2011-10-31 23:59:59'
GROUP BY date(wp.post_date)
) t
ON a.a_date = t.post_date
where a.a_date between '2011-10-01' and '2011-10-31'
group by day(a.a_date);
And I would get a table with the number of posts in my WordPress blog by author and day, similar to this:
+---------+---------+-------+------+---------+
| October | Auth1 | Auth2 | Auth3| Auth4 |
+---------+---------+-------+------+---------+
| 1 | 0 | 0 | 0 | 0 |
| 2 | 0 | 0 | 1 | 0 |
| 3 | 4 | 4 | 6 | 2 |
| 4 | 4 | 3 | 5 | 2 |
| 5 | 7 | 0 | 5 | 2 |
| 6 | 4 | 4 | 0 | 2 |
| 7 | 0 | 2 | 1 | 2 |
| 8 | 0 | 0 | 7 | 0 |
.....
etc
But what I'dlike to have is each day divided in three different rows, each one corresponding to the following time ranges:
00:00-14:30
14:31-18:15
18:16-23:59
So the table should show something like (for example, I don't know how each of the time ranges could be shown, so a good way should be day 1, time range 1 (1-1), etc).
+---------+---------+-------+------+---------+
| October | Auth1 | Auth2 | Auth3| Auth4 |
+---------+---------+-------+------+---------+
| 1-1 | 0 | 0 | 0 | 0 |
| 1-2 | 0 | 0 | 0 | 0 |
| 1-3 | 0 | 0 | 0 | 0 |
| 2-1 | 0 | 0 | 1 | 0 |
| 2-2 | 0 | 0 | 0 | 0 |
| 2-3 | 0 | 0 | 0 | 0 |
| 3-1 | 1 | 2 | 3 | 0 |
| 3-2 | 1 | 2 | 2 | 2 |
| 3-3 | 2 | 0 | 1 | 0 |
etc...
As you can see, the three rows sum is equivalent to each of the previous unique row for the day.
Is that possible?
use (UPDATE #2)
SELECT
a.a_datetm as 'October',
IFNULL(p.a1,0) as 'Auth1',
IFNULL(p.a2,0) as 'Auth2',
IFNULL(p.a50,0) as 'Auth50'
FROM
(
SELECT CONCAT (day(X.a_date), '-1') AS a_datetm
FROM all_date X
WHERE X.a_date between '2011-10-01' and '2011-10-31'
UNION ALL
SELECT CONCAT (day(Y.a_date), '-2') AS a_datetm
FROM all_date Y
WHERE Y.a_date between '2011-10-01' and '2011-10-31'
UNION ALL
SELECT CONCAT (day(Z.a_date), '-3') AS a_datetm
FROM all_date Z
WHERE Z.a_date between '2011-10-01' and '2011-10-31'
) a
LEFT OUTER JOIN
(
SELECT
CONCAT (day(wp.post_date), (CASE WHEN (TIME(wp.post_date) < '14:31:00') THEN '-1' WHEN (TIME(wp.post_date) BETWEEN '14:31:00' AND '18:15:59') THEN '-2' ELSE '-3' END )) AS a_datetm,
sum(case when wp.post_author = '1' then 1 else 0 end) as a1,
sum(case when wp.post_author = '2' then 1 else 0 end) as a2,
sum(case when wp.post_author = '50' then 1 else 0 end) as a50,
count(*) as 'All Auths'
FROM wp_posts wp
WHERE wp.post_type = 'post'
AND wp.post_date between '2011-10-01' and '2011-10-31 23:59:59'
GROUP BY CONCAT (day(wp.post_date), (CASE WHEN (TIME(wp.post_date) < '14:31:00') THEN '-1' WHEN (TIME(wp.post_date) BETWEEN '14:31:00' AND '18:15:59') THEN '-2' ELSE '-3' END ))
) p
ON a.a_datetm = p.a_datetm
ORDER BY a.a_datetm ASC;