在我的SQL查询中,我计算每天每小时的订单数量。我的查询看起来像这样:
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
我的问题是查询只返回dbo.Orders.Date中的现有小时数 例如:
Number Hour
12 3
12 5
我希望像这样返回所有时间:
Number Hour
0 0
0 1
0 2
12 3
0 4
12 5
...
0 23
有人知道如何做到这一点吗?
答案 0 :(得分:6)
使用公用表表达式创建所有小时数,然后左键加入分组总计以获得结果。
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;
答案 1 :(得分:1)
'数字表'(例如SQL, Auxiliary table of numbers)通常在您的数据库中非常有用;如果你在这里创建一个,你可以从你的数字表中选择0到23之间的所有行,对你的结果左边连接,你将得到你想要的结果,而不需要为这个查询创建一个自定义CTE或类似的。 / p>
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
(为了清楚起见,我已根据你的例子说明了这一点,但在实践中我会尽量避免在连接标准中加入函数以最大限度地提高性能。)
答案 2 :(得分:0)
您可以使用CTE
添加缺失的小时,并使用原始查询JOIN
来填充空白。
SQL声明
;WITH q (Number, Hour) AS (
SELECT 0, 1
UNION ALL
SELECT q.Number, q.Hour + 1
FROM q
WHERE q.Hour < 23
)
SELECT COALESCE(o.Number, q.Number)
, q.Hour
FROM q
LEFT OUTER JOIN (
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) }
) o ON o.Hour = q.Hour
ORDER BY
q.Hour
测试脚本
;WITH Orders (Number, Hour) AS (
SELECT 12, 3
UNION ALL SELECT 12, 5
)
, q (Number, Hour) AS (
SELECT 0, 1
UNION ALL
SELECT q.Number, q.Hour + 1
FROM q
WHERE q.Hour < 23
)
SELECT COALESCE(o.Number, q.Number)
, q.Hour
FROM q
LEFT OUTER JOIN Orders o ON o.Hour = q.Hour