sql为每月选择一条记录,并记录该月记录的总和

时间:2012-07-17 05:49:42

标签: mysql sql

我有一个拥有“约会表”和“服务表”的数据库。每个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   |
+---------------+------+-------+

有什么想法吗?

2 个答案:

答案 0 :(得分:3)

您正走在正确的轨道上,只需LEFT JOIN您查询月份表的结果。然后,结果中存在的名称将返回匹配项,并且对于结果中不存在的月份,将返回NULL。无论您喜欢什么,COALESCENVLCASE构造都可用于将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