Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

All hour of day

In my sql query, I count the number of orders in each Hour of day. My query looks something like this:

SELECT   COUNT(dbo.Uputa.ID),{ fn HOUR(dbo.Orders.Date) } AS Hour
FROM      Orders       
WHERE dbo.Orders.Date BETWEEN '2011-05-01' AND '2011-05-26' 
GROUP BY { fn HOUR(dbo.Orders.Date) }
ORDER BY Hour

My problem is that the query returns only existing Hours in dbo.Orders.Date.
For example:

Number   Hour
12         3
12         5

I want to return all hours like this:

 Number      Hour
    0          0
    0          1
    0          2
    12         3
    0          4
    12         5
   ...
    0          23

Does anybody have idea how to accomplish this?

like image 324
TheGodfather23 Avatar asked May 26 '11 09:05

TheGodfather23


2 Answers

Use a common table expression to create all hours, then left join your grouped totals to get a result.

with mycte as
(
    SELECT 0 AS MyHour
    UNION ALL
    SELECT MyHour + 1
    FROM mycte 
    WHERE MyHour + 1 < 24
)
SELECT mycte.MyHour, COALESCE(OrderCount,0) FROM mycte
LEFT JOIN 
(
    SELECT  COUNT(dbo.Uputa.ID) AS OrderCount,{ fn HOUR(dbo.Orders.Date) } AS MyHour
    FROM    Orders       
    WHERE   dbo.Orders.Date BETWEEN '2011-05-01' AND '2011-05-26' 
    GROUP BY { fn HOUR(dbo.Orders.Date) }
) h
ON
  h.MyHour = mycte.MyHour;
like image 194
Paul Alan Taylor Avatar answered Oct 16 '22 21:10

Paul Alan Taylor


A 'numbers table' (SQL, Auxiliary table of numbers for example) is in general quite a useful thing to have in your database; if you create one here you can select all rows between 0 and 23 from your numbers table, left join that against your results and you'll get the results you want without the need to create a custom CTE or similar purely for this query.

SELECT   COUNT(dbo.Uputa.ID),n.number AS Hour
FROM     (select number from numbers where number between 0 and 23) n 
             left join Orders o on n.number={ fn HOUR(dbo.Orders.Date) }
WHERE dbo.Orders.Date BETWEEN '2011-05-01' AND '2011-05-26' 
GROUP BY n.number
ORDER BY n.number

(I've worded this as per your example for clarity but in practice I'd try and avoid putting a function in the join criteria to maximise performance.)

like image 43
eftpotrm Avatar answered Oct 16 '22 19:10

eftpotrm