如果没有匹配的记录,MySql查询将获得两列的所有组合

我有一个表,其中包含服务器停机时间的记录.
我在sqlfiddle创建了这个表的简化版本.请看这里sqlfiddle
该表有各自的记录

Reason  Month   Down_Time
A       May     2
A       May     5
B       May     5
C       July    15
A       July    3
B       June    6
A       June    8
C       June    2

如果没有匹配的记录,我需要编写一个查询来获取给予Month和Reason的所有组合为NULL
举个例子:如果由于原因A,B或D,我需要在5月,6月和7月获得系统的停机时间..我期待的是……

Reason  Month   DOWNTIME
A       May     7
A       June    8
A       July    3
B       May     5
B       June    6
B       July    NULL
D       May     NULL
D       June    NULL
D       July    NULL

由于我们在给定月份的记录中没有D,因此它应该为NULL

这是我的查询:

 SELECT Reasons.reason, Months.Month,sum( a.Down_time ) AS downtime
 FROM tabledown a
 RIGHT JOIN (
 SELECT 'A' AS reason
 UNION ALL SELECT 'B' AS reason
 UNION ALL SELECT 'D' AS reason
 ) Reasons
  ON a.reason = Reasons.reason
 RIGHT JOIN (
 SELECT 'May' AS month
  UNION ALL SELECT 'June' AS month
  UNION ALL SELECT 'July' AS month
 ) Months
 ON a.Month = Months.month
 GROUP BY Reasons.reason,Months.month
 ORDER BY Reasons.reason

为什么我没有得到预期的输出:(

解决方法:

正如预期的那样,Your first outer join产生:

| REASON |  MONTH |
-------------------
|      A |    May |
|      A |    May |
|      A |   July |
|      A |   June |
|      B |    May |
|      B |   June |
|      D | (null) |

但是,因为如果连接条件至少满足一次(如果条件永远不满足则只引入NULL记录),则外连接会产生结果,因此your second outer join不会产生(B,7月)的记录;它也完全丢弃了Reason =’D’,因为连接条件没有得到满足(并且所有三个月都在其他地方得到满足):

| REASON | MONTH |
------------------
|      A |   May |
|      A |   May |
|      B |   May |
|      A |  June |
|      B |  June |
|      A |  July |

虽然您可以解决Reason =’D’by adding或a.Month IS NULL对您的连接条件的损失,但您仍然不会产生(B,7月).相反,因为您想获得每对(Reason,Month),您必须使用物化月份表CROSS JOIN您的物化原因表:

SELECT Reason, Month
FROM   
  (
    SELECT 'A' AS Reason
    UNION ALL SELECT 'B'
    UNION ALL SELECT 'D'
  ) Reasons CROSS JOIN (
    SELECT 'May' AS Month
    UNION ALL SELECT 'June'
    UNION ALL SELECT 'July'
  ) Months
| REASON | MONTH |
------------------
|      A |   May |
|      B |   May |
|      D |   May |
|      A |  June |
|      B |  June |
|      D |  June |
|      A |  July |
|      B |  July |
|      D |  July |

请在sqlfiddle查看.

然后,您只需要将结果与您的基础数据进行外连接:

SELECT Reason, Month, SUM(Down_time) downtime
FROM   
  (
    SELECT 'A' AS Reason
    UNION ALL SELECT 'B'
    UNION ALL SELECT 'D'
  ) Reasons CROSS JOIN (
    SELECT 'May' AS Month
    UNION ALL SELECT 'June'
    UNION ALL SELECT 'July'
  ) Months
  LEFT JOIN tabledown USING (Reason, Month)
GROUP BY Reason, Month
| REASON | MONTH | DOWNTIME |
-----------------------------
|      A |  July |        3 |
|      A |  June |        8 |
|      A |   May |        7 |
|      B |  July |   (null) |
|      B |  June |        6 |
|      B |   May |        5 |
|      D |  July |   (null) |
|      D |  June |   (null) |
|      D |   May |   (null) |

sqlfiddle上看到它.

上一篇:php – 生成所有可能的组合


下一篇:java – 使用字典顺序和按位算法顺序生成有限集的所有组合