【问题标题】:sql to select one record for every month with a sum of that months recordssql为每个月选择一条记录,其中包含该月记录的总和
【发布时间】:2012-07-16 00:45:17
【问题描述】:

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

有什么想法吗?

【问题讨论】:

  • 你尝试左加入了吗??
  • “我想要的是一个查询,它将始终返回 12 行(每个月一行)”
  • 如果您添加表 months 然后使用 service_price 加入月份,它将为您完成这项工作。不过,我想在没有月表的情况下这样做。
  • 还有,bhuvin 说的。如果您的约会表中每个日期都有一行,或者至少代表了每个月,那么 LEFT JOIN 应该确保您在结果中获得所有月份。
  • 试过左连接,没有骰子。在我的应用程序中,新用户在表中不会有任何应用程序,因此每个月的初始报告应该只是 0(报告将以一年作为上下文运行,但我的查询中尚未表示)@roland你是对的,我想要总共 12 行,给定年份的每个月一个(假设年 = 2012),感谢您指出这一点!

标签: mysql sql


【解决方案1】:

您在正确的轨道上,只需 LEFT JOIN 查询月份名称表的结果。然后,结果中存在的名称将返回匹配项,对于结果中不存在的月份,将返回 NULLCOALESCENVLCASE 构造,无论你喜欢什么,都可以用来将 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 并与文字日期时间进行比较,您可以获得满足要求的非常有效的查询。

此外,如果您在month(appt_date_time) 上使用GROUP BY,mysql 将确保结果也将按月升序排序。所以不需要单独的ORDER BY。 UNION 查询的“腿”的顺序也将被 mysql 保留。

【讨论】:

  • 我想我和你意见一致。我创建了一个名为“months_tbl”的表。让我失望的部分是“coalesce(appts.monthly_total,0)monthly_total” appt_tbl 中没有“monthly_total”字段。这是对左连接选择选择语句的引用吗?顺便说一句,这真是太棒了……
  • 是的,我写道:left join (...bla...) appts,所以最后一个 appts 是括号之间的整个查询的别名。所以本地名称 appts 指的是那个子查询,而在外部查询中 appts.monthly_total 指的是那个 sum(service_price) 表达式,因为它在内部查询中被赋予了monthly_total 别名。
  • 哇,我现在看到了。非常聪明,让我试一试。
  • 很好的答案,这非常有效。感谢您快速而彻底的回答!
【解决方案2】:

试试这个,它会为你工作。您需要做的就是创建一个查找表以获得更好的方法。

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

【讨论】:

    猜你喜欢
    • 2021-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-19
    相关资源
    最近更新 更多