如何连接多个表,而不会在没有匹配的情况下省略值

时间:2014-07-21 12:21:56

标签: sql database tsql data-warehouse

这个小例子基于我无数次遇到过的问题,但是我找不到最佳答案。

我想创建一份关于每个类型每月记录的事件的报告。写下面的查询。

SELECT
    d.MonthPeriod
    ,i.[Type]
    ,COUNT(*) AS [Count of Calls]
FROM
    [dbo].[FactIncident] as i
        LEFT JOIN
    [dbo].[DimDate] as d on i.DateLoggedKey = d.DateKey
GROUP BY
    d.[MonthPeriod],
    i.[Type]

这导致以下结果:

enter image description here

虽然这是正确的,但我想在早些时候看到0个已记录的电话。 DimDate包含以下内容。

enter image description here

显示所有月份每个类型的每月通话次数的最佳和/或最有效方式是什么。即使计数为0?

使用Cross Apply的想法,但结果查询很快就会变得很大。只考虑一个数据集,要求过去3年每个客户,每个类别,每个月的呼叫数量。

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

从日历表开始执行left join,以便保留所有月份:

SELECT d.MonthPeriod, i.[Type], COUNT(i.type) AS [Count of Calls]
FROM [dbo].[DimDate] d LEFT JOIN
     [dbo].[FactIncident] i
     ON i.DateLoggedKey = d.DateKey
GROUP BY d.[MonthPeriod], i.[Type];

当然,这会将type作为NULL返回没有数据的月份。

如果您想要所有类型,请在类型上使用CROSS JOIN。此示例从事实表中获取数据,但您可能有另一个包含每种类型的引用表:

SELECT d.MonthPeriod, t.[Type], COUNT(i.type) AS [Count of Calls]
FROM [dbo].[DimDate] d CROSS JOIN
     (select distinct type from factincident) t LEFT JOIN
     [dbo].[FactIncident] i
     ON i.DateLoggedKey = d.DateKey and i.type = t.type
GROUP BY d.[MonthPeriod], t.[Type];