fetching cumulative sum grouped by month on time interval - mysql

This the users table. from where i am fetching data and filling in the missing months by adding table d to query.
---------------------------------------
| uid | date_register |
---------------------------------------
| 1 | 2011-07-20 02:24:36 |
---------------------------------------
| 2 | 2012-10-03 07:37:43 |
---------------------------------------
| ... | ... ... ... ... ... |
---------------------------------------
| 300000 | 2015-12-19 04:13:51 |
---------------------------------------
I want to fetch cumulative sum grouped by month. I am using following query to do this.
SELECT d.y, d.m, p.cum_sum
FROM
(SELECT a.y, b.m
FROM (SELECT 2015 AS Y UNION ALL SELECT 2014 AS Y) a
CROSS JOIN (SELECT 1 AS m UNION ALL SELECT 2 AS m UNION ALL SELECT 3 AS m UNION ALL SELECT 4 AS m UNION ALL SELECT 5 AS m UNION ALL SELECT 6 AS m UNION ALL SELECT 7 AS m UNION ALL SELECT 8 AS m UNION ALL SELECT 9 AS m UNION ALL SELECT 10 AS m UNION ALL SELECT 11 AS m UNION ALL SELECT 12 AS m) b
WHERE CONCAT(a.y, '-', b.m, '-01') BETWEEN CURDATE() - INTERVAL 13 MONTH AND CURDATE()
ORDER BY 1, 2) d
LEFT OUTER JOIN
(SELECT year1,
month,
#cnt := #cnt + total cum_sum
FROM (
SELECT YEAR(date_register) year1,
MONTH(date_register) month,
COUNT(*) total
FROM users
WHERE date_register >= DATE_FORMAT(NOW() ,'%Y-%m-01') - INTERVAL 1 YEAR
AND useractivated = 1
GROUP BY YEAR(date_register), MONTH(date_register)
) n, (SELECT #cnt := count(*) from users
where date_register< DATE_FORMAT(NOW() ,'%Y-%m-01') - INTERVAL 1 YEAR AND useractivated = 1) u)
p ON d.m=p.month AND d.y=p.year1
ORDER BY 1 ASC, 2 ASC
but it returns null value if there is no transactions in that particular month. like following (sample data)
+------+-------+---------+
| y | m | cum_sum |
+------+-------+---------+
| 2014 | 10 | 12356 |
| 2014 | 11 | 13567 |
| 2014 | 12 | 14239 |
| 2015 | 01 | 15234 |
| 2015 | 02 | 16571 |
| 2015 | 03 | NULL |
| 2015 | 04 | 24239 |
| 2015 | 05 | 34239 |
| 2015 | 06 | 44239 |
| 2015 | 07 | 45239 |
| 2015 | 08 | 46239 |
| 2015 | 09 | 57239 |
| 2015 | 10 | 67239 |
+------+-------+---------+
so there was no transaction in march 2015, so it returning null but it should return 16571 like previous row. What I am doing wrong? Thanks.

Try this:
select a.y, b.m,
(
SELECT count(*) as cum_count
FROM users
WHERE (YEAR(date_register) = a.y and MONTH(date_register) <= b.m) or year(date_register) < a.y
) as cum_count
from
(
SELECT 2015 AS Y UNION ALL SELECT 2014 AS Y
) a
CROSS JOIN
(
SELECT 1 AS m UNION ALL SELECT 2 AS m UNION ALL SELECT 3 AS m UNION ALL SELECT 4 AS m UNION ALL SELECT 5 AS m UNION ALL SELECT 6 AS m UNION ALL SELECT 7 AS m UNION ALL SELECT 8 AS m UNION ALL SELECT 9 AS m UNION ALL SELECT 10 AS m UNION ALL SELECT 11 AS m UNION ALL SELECT 12 AS m
) b
order by a.y, b.m

Related

YTD Calculations in MySQL from (SELECT statement) including All Days of Year

Given this query...
select
sum(count) as quotes,
date
from (
select
1 as count,
DATE_FORMAT(CONVERT_TZ(createdAt, 'UTC', 'US/Pacific'), "%Y-%m-%d") as date
from quotes
where deletedAt IS NULL
) q1
group by date
order by date;
I get the following results (showing 2020-02 results only, but actual results would go back several years)...
NOTE: 2020-02-02 received 0 quotes and is missing
+-------+------------+
| count | date |
+-------+------------+
| 1 | 2020-02-01 |
| 2 | 2020-02-03 |
| 1 | 2020-02-04 |
| 1 | 2020-02-05 |
| 1 | 2020-02-06 |
| 1 | 2020-02-07 |
| 3 | 2020-02-08 |
| 3 | 2020-02-09 |
| 3 | 2020-02-10 |
| 1 | 2020-02-11 |
+-------+------------+
How do I modify the query to...
Fill in the missing days (e.g. 2020-02-02 in this example)
add the ytdCount column, which is a rolling count by year
so that the output is like this...
add the ytdCount column
\/
+-------+----------+------------+
| count | ytdCount | date |
+-------+----------+------------+
| 1 | 1 | 2020-02-01 |
| 0 | 1 | 2020-02-02 | <- was missing from previous example
| 2 | 3 | 2020-02-03 |
| 1 | 4 | 2020-02-04 |
| 1 | 5 | 2020-02-05 |
| 1 | 6 | 2020-02-06 |
| 1 | 7 | 2020-02-07 |
| 3 | 10 | 2020-02-08 |
| 3 | 13 | 2020-02-09 |
| 3 | 16 | 2020-02-10 |
| 1 | 17 | 2020-02-11 |
+-------+----------+------------+
References
I found MYSQL to calculate YTD which shows how to do this if I were selecting from a simple table, but since my "table" is actually a select statement, I'm not sure how to translate the example to my use case.
I found get all dates in the current month which shows how to generate all the dates in a month, but I need all the days for a particular year.
I solved the problem by creating two temporary tables and a UNION
Create temp table for quotes
DROP TABLE IF EXISTS __quotes__;
CREATE TABLE __quotes__ (quotes INT(11), ytdQuotes INT(11), date DATE)
ENGINE=MEMORY
AS
select
sum(count) as quotes,
NULL as ytdQuotes,
date
from (select 1 as count, DATE_FORMAT(CONVERT_TZ(createdAt, 'UTC', 'US/Pacific'), "%Y-%m-%d") as date from quotes where deletedAt IS NULL) q1 group by date order by date;
Create temp table for the date range
note: you can easily get more/less days by changing the wear clause
DROP TABLE IF EXISTS __daterange__;
CREATE TABLE __daterange__ (quotes INT(11), ytdQuotes INT(11), date DATE)
ENGINE=MEMORY
AS
select
NULL as quotes,
NULL as ytdQuotes
date
from (select date
from (
SELECT a.date
FROM (
SELECT curdate() - INTERVAL (a.a + (10 * b.a) + (100 * c.a) + + (1000 * d.a)) DAY AS date
FROM (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS a
CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS b
CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS c
CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS d) a
) daterange
where date >= "2012-11-14") daterange;
Finally, here's the query that brings it all together
select
coalesce(sum(quotes), 0) as quotes,
coalesce((select sum(q2.quotes) from __quotes__ q2 where YEAR(report.date) = YEAR(q2.date) AND q2.date <= report.date), 0) as ytdQuotes,
date
from (
select * from __quotes__
UNION ALL
select * from __daterange__
) report
group by date

Create a calendar database table like this

I would like to create a calendar SQL table like this one but for some years.
(I'm using mysql 5.7.28)
Date is DD-MM-YYYY
Is it possible?
If you are running MySQL 8.0, you can use a recursive query:
with recursive cte as (
select '2019-01-01 00:00:00' dt
union all
select dt + interval 1 hour from cte where dt < '2020-01-01' - interval 1 hour
)
select
row_number() over(order by dt) id,
date(dt) day,
time(dt) start_hour,
time(dt + interval 1 hour) end_hour
from cte
The recursive cte generates a list of datetimes between the given boundaries (here, that's year 2019), with a 1 hour increment. Then, the outer query produces the expected result, by extracting the day and hour parts.
You can adjust the boudaries and the increment as per your exact requirements.
Side note: I would suggest to retain the full datetime in the calendar table as well; there are many situation where having a proper datetime value is more convenient than separated dates and times.
Demo on DB Fiddle for the first day only:
id | day | start_hour | end_hour
-: | :--------- | :-------------- | :--------------
1 | 2019-01-01 | 00:00:00.000000 | 01:00:00.000000
2 | 2019-01-01 | 01:00:00.000000 | 02:00:00.000000
3 | 2019-01-01 | 02:00:00.000000 | 03:00:00.000000
4 | 2019-01-01 | 03:00:00.000000 | 04:00:00.000000
5 | 2019-01-01 | 04:00:00.000000 | 05:00:00.000000
6 | 2019-01-01 | 05:00:00.000000 | 06:00:00.000000
7 | 2019-01-01 | 06:00:00.000000 | 07:00:00.000000
8 | 2019-01-01 | 07:00:00.000000 | 08:00:00.000000
9 | 2019-01-01 | 08:00:00.000000 | 09:00:00.000000
10 | 2019-01-01 | 09:00:00.000000 | 10:00:00.000000
11 | 2019-01-01 | 10:00:00.000000 | 11:00:00.000000
12 | 2019-01-01 | 11:00:00.000000 | 12:00:00.000000
13 | 2019-01-01 | 12:00:00.000000 | 13:00:00.000000
14 | 2019-01-01 | 13:00:00.000000 | 14:00:00.000000
15 | 2019-01-01 | 14:00:00.000000 | 15:00:00.000000
16 | 2019-01-01 | 15:00:00.000000 | 16:00:00.000000
17 | 2019-01-01 | 16:00:00.000000 | 17:00:00.000000
18 | 2019-01-01 | 17:00:00.000000 | 18:00:00.000000
19 | 2019-01-01 | 18:00:00.000000 | 19:00:00.000000
20 | 2019-01-01 | 19:00:00.000000 | 20:00:00.000000
21 | 2019-01-01 | 20:00:00.000000 | 21:00:00.000000
22 | 2019-01-01 | 21:00:00.000000 | 22:00:00.000000
23 | 2019-01-01 | 22:00:00.000000 | 23:00:00.000000
24 | 2019-01-01 | 23:00:00.000000 | 00:00:00.000000
In earlier versions, you would typically create a large table of numbers by cross-joining subqueries, and use the number range to increment the initial date. row_number() can be emulated with a MySQL variable:
select
#id:=#id + 1 id,
date(dt) day,
time(dt) start_hour,
time(dt + interval 1 hour) end_hour,
0 prenoted
from (
select '2019-01-01' + interval d0.n + 10 * d1.n + 100 * d2.n + 1000 * d3.n hour dt
from
(
select 0 n union all select 1 union all select 2 union all select 3 union all select 4
union all select 5 union all select 6 union all select 7 union all select 8 union all select 9
) d0
cross join (
select 0 n union all select 1 union all select 2 union all select 3 union all select 4
union all select 5 union all select 6 union all select 7 union all select 8 union all select 9
) d1
cross join (
select 0 n union all select 1 union all select 2 union all select 3 union all select 4
union all select 5 union all select 6 union all select 7 union all select 8 union all select 9
) d2
cross join (
select 0 n union all select 1 union all select 2 union all select 3 union all select 4
union all select 5 union all select 6 union all select 7 union all select 8 union all select 9
) d3
where '2019-01-01' + interval d0.n + 10 * d1.n + 100 * d2.n + 1000 * d3.n hour < '2020-01-01'
) t
cross join (select #id := 0 id) i
order by dt
The above query gives you a maximum span of 10 000 hours (wich represent a little more than 416 days); you can add another cross join and update the arithmetic to handle up to 100 000 hours (and so on).
Demo on DB Fiddle for the first 24 hours.

Mysql query to get count per months

I have a table for my users that have a field named "created" that have the registration date.
How can i get a list that contains a count for the registrations number per month in last 12 months?
Like this:
Month Count
1 1232
2 2222
3 122
4 4653
... ...
12 7654
I'm not used to working with mysql, so until now i just know how to count the number of registrations in last year, not how to group that count by last 12 months. Thanks in advance!
UPDATE
Now I'm getting this, using #fthiella solution:
+------------------------------+-------------------------------+----------+
| Year(FROM_UNIXTIME(created)) | Month(FROM_UNIXTIME(created)) | Count(*) |
+------------------------------+-------------------------------+----------+
| 2012 | 4 | 9927 |
| 2012 | 5 | 5595 |
| 2012 | 6 | 4431 |
| 2012 | 7 | 3299 |
| 2012 | 8 | 429 |
| 2012 | 10 | 3698 |
| 2012 | 11 | 6208 |
| 2012 | 12 | 5142 |
| 2013 | 1 | 1196 |
| 2013 | 2 | 10 |
+------------------------------+-------------------------------+----------+
How can i force query to give me the months with count = 0?
Solution by #fthiella (thanks a lot!):
SELECT y, m, Count(users.created)
FROM (
SELECT y, m
FROM
(SELECT YEAR(CURDATE()) y UNION ALL SELECT YEAR(CURDATE())-1) years,
(SELECT 1 m UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4
UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8
UNION ALL SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12) months) ym
LEFT JOIN users
ON ym.y = YEAR(FROM_UNIXTIME(users.created))
AND ym.m = MONTH(FROM_UNIXTIME(users.created))
WHERE
(y=YEAR(CURDATE()) AND m<=MONTH(CURDATE()))
OR
(y<YEAR(CURDATE()) AND m>MONTH(CURDATE()))
GROUP BY y, m;
And the results:
+------+----+----------------------+
| y | m | Count(users.created) |
+------+----+----------------------+
| 2012 | 5 | 5595 |
| 2012 | 6 | 4431 |
| 2012 | 7 | 3299 |
| 2012 | 8 | 429 |
| 2012 | 9 | 0 |
| 2012 | 10 | 3698 |
| 2012 | 11 | 6208 |
| 2012 | 12 | 5142 |
| 2013 | 1 | 1196 |
| 2013 | 2 | 10 |
| 2013 | 3 | 0 |
| 2013 | 4 | 0 |
+------+----+----------------------+
If created is an INT field, you should use FROM_UNIXTIME function to convert it to a date field, and then MONTH function to extract the month:
SELECT Month(FROM_UNIXTIME(created)), Count(*)
FROM yourtable
WHERE FROM_UNIXTIME(created) >= CURDATE() - INTERVAL 1 YEAR
GROUP BY Month(FROM_UNIXTIME(created))
this will count all the rows that have been created in the last 12 months. Please notice that it's probably better to also group by the YEAR:
SELECT Year(FROM_UNIXTIME(created)), Month(FROM_UNIXTIME(created)), Count(*)
FROM yourtable
WHERE FROM_UNIXTIME(created) >= CURDATE() - INTERVAL 1 YEAR
GROUP BY Year(FROM_UNIXTIME(created)), Month(FROM_UNIXTIME(created))
If you need to count the registration numbers instead of the rows, you could use something like
COUNT(registration_number)
to skip null values, or
COUNT(DISTINCT registration_number)
to count only distinct ones.
Edit
If you also need to show months that have count=0, I would use a query like this that returns all of the months for the current and for the previous year:
SELECT y, m
FROM
(SELECT YEAR(CURDATE()) y UNION ALL SELECT YEAR(CURDATE())-1) years,
(SELECT 1 m UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4
UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8
UNION ALL SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12) months;
And then I'd use a LEFT JOIN, that returns all of the rows of the first query, and only the rows of the second query that matches:
SELECT y, m, Count(yourtable.created)
FROM (
SELECT y, m
FROM
(SELECT YEAR(CURDATE()) y UNION ALL SELECT YEAR(CURDATE())-1) years,
(SELECT 1 m UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4
UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8
UNION ALL SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12) months) ym
LEFT JOIN yourtable
ON ym.y = YEAR(FROM_UNIXTIME(yourtable.created))
AND ym.m = MONTH(FROM_UNIXTIME(yourtable.created))
WHERE
(y=YEAR(CURDATE()) AND m<=MONTH(CURDATE()))
OR
(y<YEAR(CURDATE()) AND m>MONTH(CURDATE()))
GROUP BY y, m
(please notice that here I am considering just the last 12 months, so if we are in the middle April 2013 it will count rows in the interval May 2012 - April 13, if this is not the correct behaviour please let me know)
SELECT MONTH(reg_date) , COUNT(reg_date)
FROM your_table
WHERE reg_date >= NOW() - INTERVAL 1 YEAR
GROUP BY MONTH(reg_date)
In case this helps anyone else, I additionally wanted this query but for a given time interval that was not necessarily the last 12 months (also with a timestamp for the date):
set #start='2013-05-01 00:00:00';
set #end='2015-03-31 00:00:00';
SELECT YEAR(FROM_UNIXTIME(yourtable.created_date)), MONTH(FROM_UNIXTIME(yourtable.created_date)), COUNT(yourtable.created_date)
FROM yourtable
WHERE created_date BETWEEN UNIX_TIMESTAMP( DATE(#start) ) AND UNIX_TIMESTAMP( DATE(#end) )
GROUP BY YEAR(FROM_UNIXTIME(yourtable.created_date)), MONTH(FROM_UNIXTIME(yourtable.created_date))
ORDER BY YEAR(FROM_UNIXTIME(yourtable.created_date)), MONTH(FROM_UNIXTIME(yourtable.created_date));

To select matching strings in 2 tables

TableA
Id | M | D | Y |
=======================
1 | 10 | 28 | 2012 |
2 | 11 | 29 | 2012 |
3 | 12 | 30 | 2012 |
TableB
Id | M | D | Y |
=======================
4 | 09 | 28 | 2012 |
5 | 11 | 29 | 2012 |
6 | 01 | 30 | 2013 |
I will search by M and D
Ex: If matching M = 11 AND D = 29 ... so will return ID(s) 2 , 5
I can only find by one table like this
mysql_query("SELECT * FROM TableA WHERE M='11' AND Y='29' ORDER BY D ASC , Id DESC;";)
But how to find in multiple tables ?
Use the UNION clause between two SELECTs
(SELECT Id, M, D, Y FROM TableA WHERE M='11' AND Y='29')
UNION
(SELECT Id, M, D, Y FROM TableB WHERE M='11' AND Y='29')
ORDER BY D ASC , Id DESC
You better use UNION ALL (in case tableB has identical records) to get all the records. Otherwise just UNION will do.
SELECT * FROM TableA WHERE M='11' AND Y='29'
UNION ALL
SELECT * FROM TableB WHERE M='11' AND Y='29'
ORDER BY D ASC , Id DESC;
SELECT * FROM TableA WHERE M='11' AND Y='29'
UNION
SELECT * FROM TableB WHERE M='11' AND Y='29'
ORDER BY D ASC , Id DESC;

MySQL: filling empty fields with zeroes when using GROUP BY

I've got MySQL table
CREATE TABLE cms_webstat (
ID int NOT NULL auto_increment PRIMARY KEY,
TIMESTAMP_X timestamp DEFAULT CURRENT_TIMESTAMP,
# ... some other fields ...
)
which contains statistics about site visitors.
For getting visits per hour I use
SELECT
hour(TIMESTAMP_X) as HOUR
, count(*) AS HOUR_STAT
FROM cms_webstat
GROUP BY HOUR
ORDER BY HOUR DESC
which gives me
| HOUR | HOUR_STAT |
| 24 | 15 |
| 23 | 12 |
| 22 | 9 |
| 20 | 3 |
| 18 | 2 |
| 15 | 1 |
| 12 | 3 |
| 9 | 1 |
| 3 | 5 |
| 2 | 7 |
| 1 | 9 |
| 0 | 12 |
And I'd like to get following:
| HOUR | HOUR_STAT |
| 24 | 15 |
| 23 | 12 |
| 22 | 9 |
| 21 | 0 |
| 20 | 3 |
| 19 | 0 |
| 18 | 2 |
| 17 | 0 |
| 16 | 0 |
| 15 | 1 |
| 14 | 0 |
| 13 | 0 |
| 12 | 3 |
| 11 | 0 |
| 10 | 0 |
| 9 | 1 |
| 8 | 0 |
| 7 | 0 |
| 6 | 0 |
| 5 | 0 |
| 4 | 0 |
| 3 | 5 |
| 2 | 7 |
| 1 | 9 |
| 0 | 12 |
How should I modify the query to get such result (with one mysql query, without creating temporary tables)?
Is it possible to get such result with one MySQL query?
Create another table with a single column,
CREATE TABLE hours_list (
hour int NOT NULL PRIMARY KEY
)
Fill it with all 24 hours.
Then do a join on that table to fill in the zeroes.
SELECT
hs.hour as HOUR, COUNT(ws.ID) AS HOUR_STAT
FROM hours_list hs
LEFT JOIN cms_webstat ws ON hs.hour = hour(ws.TIMESTAMP_X)
GROUP BY hs.hour
ORDER BY hs.hour DESC
This is just the 'why it is not returning` part. Marcus' answer covers the 'how to' part.
The SQL
SELECT
hour(TIMESTAMP_X) as HOUR
, count(*) AS HOUR_STAT
FROM cms_webstat
GROUP BY HOUR
ORDER BY HOUR DESC
gets the count of the records per hour, for the timestamps present in the table
It does not give the details of what is not present in the table. Since there is no recors for the timestamp corresponding to the hour 8 (from your example) the SQL does not return any records.
I've finaly found the answer.
Maybe I'm insane, but this works.
SELECT HOUR, max(HOUR_STAT) as HOUR_STAT FROM (
(
SELECT HOUR(TIMESTAMP_X) as HOUR, count(*) as HOUR_STAT
FROM cms_webstat
WHERE date(TIMESTAMP_X) = date(now())
)
UNION (SELECT 0 as HOUR, 0)
UNION (SELECT 1 as HOUR, 0)
UNION (SELECT 2 as HOUR, 0)
UNION (SELECT 3 as HOUR, 0)
UNION (SELECT 4 as HOUR, 0)
UNION (SELECT 5 as HOUR, 0)
UNION (SELECT 6 as HOUR, 0)
UNION (SELECT 7 as HOUR, 0)
UNION (SELECT 8 as HOUR, 0)
UNION (SELECT 9 as HOUR, 0)
UNION (SELECT 10 as HOUR, 0)
UNION (SELECT 11 as HOUR, 0)
UNION (SELECT 12 as HOUR, 0)
UNION (SELECT 13 as HOUR, 0)
UNION (SELECT 14 as HOUR, 0)
UNION (SELECT 15 as HOUR, 0)
UNION (SELECT 16 as HOUR, 0)
UNION (SELECT 17 as HOUR, 0)
UNION (SELECT 18 as HOUR, 0)
UNION (SELECT 19 as HOUR, 0)
UNION (SELECT 20 as HOUR, 0)
UNION (SELECT 21 as HOUR, 0)
UNION (SELECT 22 as HOUR, 0)
UNION (SELECT 23 as HOUR, 0)
)
AS `combined_table`
GROUP BY HOUR
ORDER BY HOUR DESC
One MySQL query as desired.
$sql = 'SELECT g, MAX(v) AS v, MAX(c) AS c FROM (';
$sql .= '(SELECT DATE_FORMAT(viewed, \'%d.%m.%Y\') AS g, COUNT(1) AS v, 0 AS c FROM '.$this->prefix.'view WHERE campaignid IN ('.join(', ',$ids).') GROUP BY g)';
$sql .= ' UNION (SELECT DATE_FORMAT(clicked, \'%d.%m.%Y\') AS g, 0 AS v, COUNT(1) AS c FROM '.$this->prefix.'clicks WHERE campaignid IN ('.join(', ',$ids).') GROUP BY g)';
$today = strtotime("00:00:00");
for ($i=$today; $i>=time()-30*86400; $i-=86400) {
$sql .= ' UNION (SELECT \''.date('d.m.Y',$i).'\' AS g, 0 AS v, 0 AS c)';
}
$sql .= ') AS tmp GROUP BY g ORDER BY g DESC';
$chart = DB::getAll($sql);
p($chart);
Thanks! Made it! From 2 tables, clicks and views, joined.. works. ajaxel.com