3

我有一个具有“约会表”和“服务表”的数据库。每个appt都有一个服务,每个服务都有一个价格。我想要的是一个查询,它将始终返回 12 行(每个月一行)并包含月份 appts 的总和(基于它的服务 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  |
+---------------+------+-------+

问题是如果一个月没有任何应用程序,我不会在查询中返回该月。我希望那个月有一个记录,只要它的“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   |
+---------------+------+-------+

有任何想法吗?

4

2 回答 2

3

您走在正确的轨道上,只是LEFT JOIN您查询月份名称表的结果。然后结果中存在的名称将返回一个匹配项,并且 aNULL将返回那些不在您的结果中的月份。一个COALESCEor NVLorCASE结构,无论你喜欢什么,都可以用来把它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 BYmonth(appt_date_time)mysql 上将确保结果也将按月升序排序。所以不需要单独的ORDER BY. UNION 查询的“腿”的顺序也将由 mysql 保留。

于 2012-07-17T06:04:01.113 回答
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
于 2012-07-17T06:25:50.680 回答