SQL显示过去12个月,包括没有记录的月份

时间:2016-06-02 18:29:44

标签: sql-server

我工作的公司有一个消息传递系统,我需要按照过去12个月按月合并的模板计算发送的消息,如下例所示。如果模板在指定的月份没有消息,则它应该显示为零(换句话说,如果我有2个模板,结果将是24行,每个模板12个月):

-----------------------------
| date    | template | qqty |
-----------------------------
| 01/2015 | tpl1     |  100 |
-----------------------------
| 01/2015 | tpl2     |  10  |
-----------------------------
| 02/2015 | tpl1     |  90  |
-----------------------------
| 02/2015 | tpl2     |  0   |
-----------------------------

我正在努力实现在thisthis帖子中提出/提交的结果。我们使用SQLSERVER而不是MySQL。

基本上系统有两个表:

MESSAGE

---------------------------------
| msg_id | tpl_id | date        |
---------------------------------
| 1      | 1      |  03/01/2015 |
---------------------------------
| 2      | 1      |  15/01/2015 |
---------------------------------
| 3      | 2      |  04/01/2015 |
---------------------------------
| 4      | 1      |  22/02/2015 |
---------------------------------

TEMPLATE

---------------------
| tpl_id | tpl_name |
---------------------
| 1      | tpl1     | 
---------------------
| 2      | tpl2     |
---------------------

我做了以下SQL。它一直有效,直到我启用模板连接。如果我启用它,结果将只显示系统记录的月份......

SELECT
  years.y, months.m, --tpl.tpl_name,
  COUNT(msg.msg_id) AS Total 
FROM (
  SELECT year(getdate())     AS y UNION ALL
  SELECT year(getdate()) - 1 AS y 
) years
CROSS JOIN (
  SELECT  1 AS m UNION ALL
  SELECT  2 AS m UNION ALL
  SELECT  3 AS m UNION ALL
  SELECT  4 AS m UNION ALL
  SELECT  5 AS m UNION ALL
  SELECT  6 AS m UNION ALL
  SELECT  7 AS m UNION ALL
  SELECT  8 AS m UNION ALL
  SELECT  9 AS m UNION ALL
  SELECT 10 AS m UNION ALL
  SELECT 11 AS m UNION ALL
  SELECT 12 AS m
) months
LEFT JOIN MESSAGE msg ON YEAR(msg.date) = years.y AND MONTH(msg.date) = months.m
--LEFT JOIN TEMPLATE tpl ON tpl.tpl_id = msg.tpl_id
WHERE 
    (CONVERT(DATETIME, CONVERT(VARCHAR(4), YEAR(GETDATE())) + '-' + CONVERT(VARCHAR(2), MONTH(GETDATE())) + '-01')) >= DATEADD(month, -12, GETDATE())
    AND (CONVERT(DATETIME, CONVERT(VARCHAR(4), YEAR(GETDATE())) + '-' + CONVERT(VARCHAR(2), MONTH(GETDATE())) + '-01')) <= GETDATE()
GROUP BY years.y, months.m--, tpl.tpl_name
ORDER BY years.y, months.m--, tpl.tpl_name

我的SQL知识是基本的。我试图将连接更改为RIGHT,OUTER等,但没有成功。

拜托,您能帮我指出如何实现它吗?

2 个答案:

答案 0 :(得分:1)

首先交叉连接TEMPLATE然后离开加入消息。

FROM    (...
        ) years
        CROSS JOIN (...
                   ) months
        CROSS JOIN TEMPLATE tpl
        LEFT JOIN MESSAGE msg ON YEAR(msg.date) = years.y
                                 AND MONTH(msg.date) = months.m AND tpl.tpl_id = msg.tpl_id

答案 1 :(得分:1)

从概念上讲,您需要构建要报告的项目列表(年x月x模板),然后(通过外部联接)处理列表中每个项目的数据。在这里,我将TEMPLATE上的连接更改为交叉连接:

SELECT
  years.y, months.m, tpl.tpl_name,
  COUNT(msg.msg_id) AS Total 
FROM (
  SELECT year(getdate())     AS y
  UNION ALL SELECT year(getdate()) - 1 AS y 
     ) years
CROSS JOIN (
  SELECT  1 AS m UNION ALL
  SELECT  2 AS m UNION ALL
  SELECT  3 AS m UNION ALL
  SELECT  4 AS m UNION ALL
  SELECT  5 AS m UNION ALL
  SELECT  6 AS m UNION ALL
  SELECT  7 AS m UNION ALL
  SELECT  8 AS m UNION ALL
  SELECT  9 AS m UNION ALL
  SELECT 10 AS m UNION ALL
  SELECT 11 AS m UNION ALL
  SELECT 12 AS m
) months
CROSS JOIN TEMPLATE tpl  --  Assumes there are just the two templates in the table
LEFT JOIN MESSAGE msg
  ON YEAR(msg.date) = years.y
   AND MONTH(msg.date) = months.m
   AND msg.tpl_id = tpl.tpl_id
WHERE 
        (CONVERT(DATETIME, CONVERT(VARCHAR(4), YEAR(GETDATE())) + '-' + CONVERT(VARCHAR(2), MONTH(GETDATE())) + '-01')) >= DATEADD(month, -12, GETDATE())
    AND (CONVERT(DATETIME, CONVERT(VARCHAR(4), YEAR(GETDATE())) + '-' + CONVERT(VARCHAR(2), MONTH(GETDATE())) + '-01')) <= GETDATE()
GROUP BY years.y, months.m--, tpl.tpl_name
ORDER BY years.y, months.m--, tpl.tpl_name

(我无法测试查询,但应该很好。)