SELECT month(dateofappointment), COUNT(*) 'NumberOfAppointments'
FROM appointment
WHERE YEAR(dateofappointment) = '2016'
GROUP BY MONTH(dateofappointment)
这显示了我所有月份,但12月不存在,因为那一年没有任何约会。我如何将12月显示为0?
答案 0 :(得分:0)
要解决这些类型的查询,通常有助于将它们表达为一系列要求,这样可以更容易解决。
如果结果未按预期显示,请在识别时根据新要求更新您的需求声明,然后重试:
我现在看到你有两个要求:
好的,所以这很详细,但是你看到你的查询中缺少的是一个声明,它定义了2016年每个月的 1行' 1行。因此,您需要首先手动或通过递归来构建该记录集。
MySQL目前不支持递归公用表表达式,这在许多其他RDBMS中都是一个微不足道的概念
但如果MySQL不支持递归,我们的选择是什么?以下是SO的其他一些尝试:
这可能听起来有点像黑客攻击,但你可以使用数据库中任何超过12行且具有自动递增字段的表,哦,并且从1开始(或以下)播种。忘记这是对还是错,它会起作用:
SELECT Id
FROM LogEvent -- An arbitrary table that I know has records starting from 1
WHERE Id BETWEEN 1 AND 12
所以这很麻烦,但我们可以实现一个行计数功能,这样我们就可以使用任何包含12行或更多行的表,无论id还是种子,都可以从MySQL get row number on select - Answer by Mike Cialowicz偷走它
SET @rank=0;
SELECT @rank:=@rank+1 AS rank
FROM orders
WHERE rank <= 12
现在我们可以将此结果集中缺失的行合并到原始查询中,或者使用连接运算符。使用union的第一个解决方案。
通常使用UNION ALL将缺少的行注入记录集,因为它将预期结果查询与异常或默认结果分开。有时这种语法可以更容易地解释预期的操作
SET @rank = 0;
SELECT month(dateofappointment) as Month, COUNT(*) 'NumberOfAppointments'
FROM appointment
WHERE YEAR(dateofappointment) = '2016'
GROUP BY MONTH(dateofappointment)
UNION ALL
SELECT rank, 0
FROM (
SELECT @rank:=@rank+1 AS rank
FROM rows
WHERE @rank < 12
) months
WHERE NOT EXISTS (SELECT dateofappointment
FROM appointment
WHERE YEAR(dateofappointment) = '2016' AND MONTH(dateofappointment) = months.rank)
ORDER BY Month
但这会导致丑陋的查询。您也可以使用左连接加入有关约会计数的月份查询,但此处的意图更难识别。
SET @rank = 0;
SELECT months.rank, COUNT(appointment.dateofappointment)
FROM (
SELECT @rank:=@rank+1 AS rank
FROM rows
WHERE @rank < 12
) months
LEFT OUTER JOIN appointment ON months.rank = Month(appointment.dateofappointment) AND YEAR(dateofappointment) = '2016'
GROUP BY months.rank
I have saved these queries into a SqlFiddle so you can see the results: http://sqlfiddle.com/#!9/99d485/4
正如我上面所指出的,这在MS SQL和Oracle RDBMS中是微不足道的,我们可以通过递归公用表表达式(CTE)动态生成值序列。对于家中的玩家来说,这是MS SQL Server 2014中的一个实现。这个例子有点进化,使用from和to来动态过滤结果
-- Dynamic MS SQL Example using recursive CTE
DECLARE @FromDate Date = '2016-01-01'
DECLARE @ToDate Date = '2016-12-31'
;
WITH Months(Year, Month, Date) AS
(
SELECT Year(@FromDate), Month(@FromDate), @FromDate
UNION ALL
SELECT Year(NextMonth.Date), Month(NextMonth.Date), NextMonth.Date
FROM Months
CROSS APPLY (SELECT DateAdd(m, 1, Date) Date) NextMonth
WHERE NextMonth.Date < @ToDate
)
SELECT Months.Year, Months.Month, COUNT(*) as 'NumberOfAppointments'
FROM Months
LEFT OUTER JOIN appointment ON Year(dateofappointment) = Months.Year AND Month(dateofappointment) = Months.Month
GROUP BY Months.Year, Months.Month