我有一个拥有“约会表”和“服务表”的数据库。每个appt都有服务,每项服务都有价格。我想要的是一个查询,它将始终返回12行(每个月一行)并包含月份的总和(基于它的服务ID)。到目前为止,我有:
select sum(service_price) as monthly_total,
year(appt_date_time) as year,
monthname(appt_date_time) as month
from appt_tbl
join services_tbl on appt_tbl.service_id = services_tbl.service_id
group by month(appt_date_time),
year(appt_date_time)
order by month(appt_date_time) asc;
目前,这会返回如下内容:
+---------------+------+-------+
| monthly_total | year | month |
+---------------+------+-------+
| 120.00 | 2012 | July |
+---------------+------+-------+
问题是,如果一个月没有任何appts,我不会在查询中返回该月份。我希望那个月有一个记录,只要它的“monthly_total”等于零。
以下是我希望返回的查询:
+---------------+------+-------+
| monthly_total | year | month |
+---------------+------+-------+
| 0.00 | 2012 | Jan |
+---------------+------+-------+
| 0.00 | 2012 | Feb |
+---------------+------+-------+
| 0.00 | 2012 | March |
+---------------+------+-------+
| 0.00 | 2012 | April |
+---------------+------+-------+
| 0.00 | 2012 | May |
+---------------+------+-------+
| 0.00 | 2012 | June |
+---------------+------+-------+
| 120.00 | 2012 | July |
+---------------+------+-------+
| 0.00 | 2012 | August|
+---------------+------+-------+
| 0.00 | 2012 | Sept |
+---------------+------+-------+
| 0.00 | 2012 | Oct |
+---------------+------+-------+
| 0.00 | 2012 | Nov |
+---------------+------+-------+
| 0.00 | 2012 | Dec |
+---------------+------+-------+
有什么想法吗?
答案 0 :(得分:3)
您正走在正确的轨道上,只需LEFT JOIN
您查询月份表的结果。然后,结果中存在的名称将返回匹配项,并且对于结果中不存在的月份,将返回NULL
。无论您喜欢什么,COALESCE
或NVL
或CASE
构造都可用于将NULL
转换为直线0
。
您不需要制作真正的月份表,您可以使用内联视图 - 只需生成所有月份数据的查询。
select months.month, coalesce(appts.monthly_total, 0) monthly_total
from (
select 'January' as month
union all select 'February'
union all select 'March'
...etc...
union all select 'December'
) months
left join (
select sum(service_price) as monthly_total,
monthname(appt_date_time) as month
from appt_tbl
inner join services_tbl
on appt_tbl.service_id = services_tbl.service_id
where appt_date_time between '2012-01-01 00:00:00'
and '2012-12-31 23:59:59'
group by month(appt_date_time)
) appts
on months.month = appts.month
至于返回特定年份的每一个,请查看WHERE条件。我觉得appt_date_time是一个日期时间或时间戳。你不想写YEAR(appt_date_time)= 2012,因为这会破坏在该列上使用索引的可能性(我假设该列显示为索引中的第一列)。通过使用BETWEEN ... AND并与文字日期时间进行比较,您可以获得满足要求的非常高效的查询。
另外,如果GROUP BY
month(appt_date_time)
上的ORDER BY
将确保结果按月按升序排序。所以不需要单独的{{1}}。 mysql也将保留UNION查询的“分支”的顺序。
答案 1 :(得分:1)
试试这个,它会对你有用。您需要做的就是创建一个查找表以获得更好的方法。
CREATE TABLE MONTHS(MON CHAR(3))
INSERT INTO MONTHS
SELECT 'Jan' UNION ALL
SELECT 'Feb' UNION ALL
SELECT 'Mar' UNION ALL
SELECT 'Apr' UNION ALL
SELECT 'May' UNION ALL
SELECT 'Jun' UNION ALL
SELECT 'Jul' UNION ALL
SELECT 'Aug' UNION ALL
SELECT 'Sep' UNION ALL
SELECT 'Oct' UNION ALL
SELECT 'Nov' UNION ALL
SELECT 'Dec'
CREATE TABLE Appointments(App int, Year int, Month CHAR(3))
INSERT INTO Appointments
SELECT 120,2012,'Jul' UNION ALL
SELECT 120,2013,'Apr'
SELECT sum(isnull(App,0)) monthly_total, b.Mon , b.Year FROM Appointments a
RIGHT JOIN (SELECT DISTINCT Year,Mon FROM Appointments CROSS JOIN MONTHS) b
ON a.Month=b.MON AND a.Year=b.Year
GROUP BY b.Mon,b.Year