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
Related
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.
There is a table which has data as such:
-----------------------
| id | date |
-----------------------
| 1 | 2016-07-11 |
| 2 | 2016-07-11 |
| 3 | 2016-07-15 |
| 4 | 2016-07-15 |
| 5 | 2016-07-15 |
| 6 | 2016-07-16 |
| 7 | 2016-07-19 |
| 8 | 2016-07-20 |
-----------------------
I want to get a date range (all dates) and the count of IDs for each date, returning 0 when no records exist.
If run for dates between 2016-07-10 to 2016-07-20, the result should look like this:
--------------------------
| date | count(id) |
--------------------------
| 2016-07-10 | 0 |
| 2016-07-11 | 2 |
| 2016-07-12 | 0 |
| 2016-07-13 | 0 |
| 2016-07-14 | 0 |
| 2016-07-15 | 3 |
| 2016-07-16 | 1 |
| 2016-07-17 | 0 |
| 2016-07-18 | 0 |
| 2016-07-19 | 1 |
| 2016-07-20 | 1 |
--------------------------
I've found solutions for getting a date range but couldn't figure out how to get it to count the IDs that exist for those dates within a table.
Thanks!
I figured this out by modifying the query given in the solution for getting all dates.
The following query returns all dates, and counts of the IDs if any records exist:
select d.date, count(v.id) from
(select adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) date from
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4) d
left join visitors v on d.date = v.date
where d.date between '2016-06-01' and '2016-06-30'
group by d.date
order by d.date
Courtesy for getting the dates range goes to #mark-bannister and a simple join on the query matching for results, and sorting gets the solution.
Please try the following, basically a group by is needed that would help you get the desired result. Also have the where condition with range as needed
SELECT date ,count(date) from datetable group by date;
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));
I have a table that stores the amount of errors according to what alarm-id it is. The table looks something like this:
|----DATE----|---ALARM_ID---|---COUNTER---|
| 2012-01-01 | 1 | 32 |
| 2012-01-01 | 2 | 28 |
| 2012-01-02 | 1 | 12 |
| 2012-01-02 | 2 | 23 |
| 2012-01-03 | 1 | 3 |
| 2012-01-03 | 2 | 9 |
| 2012-01-05 | 1 | 8 |
| 2012-01-05 | 2 | 1 |
| 2012-01-07 | 1 | 102 |
| 2012-01-07 | 2 | 78 |
Notice the gap between date (2012-01-03 - 2012-01-05) and (2012-01-05 - 2012-01-07). On these dates there isn't any data because the system, that my program is monitoring, haven't reported any errors at that date. What I'm looking for is a SQL SELECT query that returns the total amount of errors on each date, for example:
|----DATE----|---COUNTER---|
| 2012-01-01 | 60 |
| 2012-01-02 | 35 |
| 2012-01-03 | 12 |
| 2012-01-04 | 0 |
| 2012-01-05 | 9 |
| 2012-01-06 | 0 |
| 2012-01-07 | 180 |
I have a query that returns ID's even if they doesn't exist in the table, and if the ID doesn't exist, return the ID anyway with the COUNTER value 0. As such:
BEFORE AFTER
|---ID---|---COUNTER---| |---ID---|---COUNTER---|
| 1 | 2 | | 1 | 2 |
| 2 | 6 | | 2 | 6 |
| 3 | 1 | --> | 3 | 1 |
| 5 | 9 | | 4 | 0 |
| 6 | 10 | | 5 | 9 |
| 6 | 10 |
| 7 | 0 |
| 8 | 0 |
The query goes like this:
select t.num as ID, coalesce(yt.COUNTER, 0)
from all_stats yt right join
( select t1.num + t2.num * 10 + t3.num * 100 + t4.num * 1000 as num
from ( select 1 as num union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9 union select 0 ) t1 cross join
( select 1 as num union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9 union select 0 ) t2 cross join
( select 1 as num union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9 union select 0 ) t3 cross join
( select 1 as num union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9 union select 0 ) t4 )
t on yt.ID = t.num
where (t.num between (select min(ID) from all_stats) and (select max(ID) from all_stats)) order by ID
I can't figure out how I can change this query when it's regarding dates. Can someone please help me on this issue?
I'm using MySQL
Thanks in advance, Steve-O
The exact details will depend on the DBMS, and on the nature of the database (e.g., OLAP-oriented vs. OLTP-oriented), but one common general approach is to create an auxiliary calendar table that represents dates as a dimension. Then you can use regular JOINs, rather than having to use complex logic to generate missing dates.
The answers to this StackOverflow question describe how to apply this approach on MySQL.
You can use a similar approach for numbers, by the way, by having a numbers tables; I've never done that myself for numbers, but it seems to be a popular idea; see this dba.stackexchange.com question.
If you're using SQL Server 2005 or above you can use a CTE (if not, a loop or other sql technique to populate a table with the dates in the range). Note also there is a limit to the levels of recursion within a CTE.
declare #dateRange table
(
dateBegin datetime,
dateEnd datetime
)
insert into #dateRange (dateBegin, dateEnd)
values ('2012-01-01', '2012-01-07')
;with cte (d)
as (select dateBegin as d
from #dateRange tbl
where datediff(day, tbl.dateBegin, tbl.dateEnd) <= 100
union all
select dateadd(day, 1, cte.d) as d
from cte
inner join #dateRange tbl on cte.d < tbl.dateEnd)
Then get the full results either using the CTE or a temporary table that contains the set of dates in the range:
select cte.d, sum(isnull(e.errorCounter, 0))
from cte
left outer join #errors e on e.errorDate = cte.d
group by cte.d
order by cte.d
You really should handle this at the application layer (ie iterate over the known date range and pull the non-zero vals from the resultset) or fix your table to always include the dates needed if you MUST have a database-centered solution. There's no really good way to generate, on the fly, a set of dates to use in building a continuous date range query.
You can see this for some examples of DB scripting solutions:
Return temp table of continuous dates
But I think you're posing the wrong question. Fix the database to include what you need, or fix how you're generating your report. Databases aren't meant to do interpolation and data generation.
Using the following query to get a hourly breakdown of transactions
SELECT hour(Stamp) AS Hour, count(1) AS Count FROM Transactions GROUP by 1 WITH ROLLUP;
Results in the following output:
+------+-------+
| Hour | Count |
+------+-------+
| 0 | 269 |
| 1 | 342 |
| 2 | 319 |
| 3 | 284 |
| 4 | 235 |
| 5 | 174 |
| 6 | 91 |
| 7 | 54 |
| 8 | 31 |
| 9 | 21 |
| 10 | 21 |
| 11 | 1 |
| NULL | 1842 |
+------+-------+
I would like to display the hours with 0 transactions (e.g. in this example, every hour between 12 and 23 would show '0'). What would be the simplest way to do this?
try something like this (the -1 hour_id is for the rollup total):
drop table if exists hours;
create table hours(hour_id tinyint primary key) engine=innodb;
insert into hours (hour_id) values
(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),
(13),(14),(15),(16),(17),(18),(19),(20),(21),(22),(23),(0),(-1);
select
h.hour_id,
if(t.counter is null, 0, t.counter) as counter
from
hours h
left outer join
(
select
if(hour(stamp) is null, -1, hour(stamp)) as hour_id,
count(stamp) as counter
from
transactions group by stamp with rollup
) t
on h.hour_id = t.hour_id;
if you want it by months create a months table 1..12 + -1 etc...
SELECT Temp.Hour, COUNT(1)
FROM (
SELECT 0 AS Hour UNION
SELECT 1 UNION
SELECT 2 UNION
SELECT 3 UNION
SELECT 4 UNION
SELECT 5 UNION
SELECT 6 UNION
SELECT 7 UNION
SELECT 8 UNION
SELECT 9 UNION
SELECT 10 UNION
SELECT 11 UNION
SELECT 12 UNION
SELECT 13 UNION
SELECT 14 UNION
SELECT 15 UNION
SELECT 16 UNION
SELECT 17 UNION
SELECT 18 UNION
SELECT 19 UNION
SELECT 20 UNION
SELECT 21 UNION
SELECT 22 UNION
SELECT 23
) AS Temp
LEFT JOIN Transactions
ON Temp.Hour = HOUR(Transactions.Stamp)
GROUP BY Temp.Hour
ORDER BY Temp.Hour