与日期维度连接但不希望具有值的日期为NULL

时间:2014-08-08 21:22:33

标签: sql left-join

我有一个问题:

 SELECT 
    d.FiscalMonth,
    d.FiscalMonthOfYear,
    p.Name
 FROM
     DimDate d
     LEFT JOIN FactSales f on f.SaleDate=d.PKDate
     LEFT JOIN DimPerson p on p.PersonId=f.PersonId
 WHERE d.FiscalYear='2014/7/1'
 group by d.FiscalMonth, d.FiscalMonthOfYear, p.Name
 ORDER BY d.FiscalMonthOfYear asc, p.PersonID asc

这给了我这些结果:

enter image description here

哪个都没关系,我想包括所有月份,甚至是那些没有数据的月份。 (在本例中为FiscalMonth 2-12。)

我遇到的问题是有一个NULL值,我有数据,IE。 FiscalMonthOfYear 1.红色框。

我如何才能为FiscalMonth = 2014-07-01返回那个“NULL”?我尝试过各种各样的where子句,但是当我从结果中删除“NULL”值时,我也删除了我想要的所有(IE.FiscalMonthOfYear 2-12)

非常感谢任何帮助或指导!

谢谢! -Russ

更新

DimDate表有主键PKDate,每个日期都是一行:

  DimDate
  PKDate ....
  2014-07-01
  2014-07-02
  2014-07-03
  etc.

FaceSales表在给定的一天中有一个或多个销售交易:

  FactSales
  SaleDate       Amount
  2014-07-01     34.99
  2014-07-01     21.89
  2014-07-02     24.77
  2014-07-04     22.77

问题是FactSales可能在某一天没有销售。所以我的查询是找到没有交易的一天(或多天),并且由于LEFT JOIN正在返回它。我如何去除这个结果,因为它不在我的结果中?

  SELECT
       d.PKDate
       ,f.SaleDate

 FROM
     DimDate d
     LEFT JOIN FactSales f on f.SaleDate=d.PKDate
     LEFT JOIN DimPerson p on p.PersonId=f.PersonId
 WHERE d.FiscalYear='2014/7/1'
 ORDER BY d.PKDate

enter image description here

2 个答案:

答案 0 :(得分:1)

问题源于你实际上是在尝试同时做两件事:

  • 您希望所有与财务月销售额相关的名称为 至少一次销售
  • 您希望所有会计月份都有额外的行,但没有 销售

正如在这些情况下经常发生的那样......你应该解决两个不同的问题然后把结果放在一起(在这种特定情况下使用UNION)。

这样的事情:

SELECT * FROM
(
  SELECT DISTINCT
    d.FiscalMonth,
    d.FiscalMonthOfYear,
    p.Name
  FROM DimDate   d
  JOIN FactSales f ON f.SaleDate=d.PKDate
  JOIN DimPerson p ON p.PersonId=f.PersonId
  WHERE d.FiscalYear='2014/7/1'
) UNION (
  SELECT
    d.FiscalMonth,
    d.FiscalMonthOfYear,
    NULL AS Name
  FROM      DimDate   d
  LEFT JOIN FactSales f ON f.SaleDate=d.PKDate
  WHERE d.FiscalYear='2014/7/1'
  GROUP BY d.FiscalMonth, d.FiscalMonthOfYear, p.Name
  HAVING COUNT(f.SaleDate)=0
)
ORDER BY FiscalMonthOfYear asc, PersonID ASC

我还没有测试过,可能有更好的方法可以解决第二部分(SUBSELECT,EXISTS),但这取决于您使用的引擎。

答案 1 :(得分:0)

您可以按如下方式进行内部联接:

SELECT 
    d.FiscalMonth,
    d.FiscalMonthOfYear,
    p.Name
 FROM
     DimDate d
     INNER JOIN FactSales f on f.SaleDate=d.PKDate
     LEFT JOIN DimPerson p on p.PersonId=f.PersonId
 WHERE d.FiscalYear='2014/7/1'
 group by d.FiscalMonth, d.FiscalMonthOfYear, p.Name
 ORDER BY d.FiscalMonthOfYear asc, p.PersonID asc

内连接执行两个表的并集,而不优先使用左表。有关联接的更多信息,请阅读此博客:Visual representation of sql joins 其中声明INNER JOIN 将返回左表(表A)中右表中具有匹配记录的所有记录(表B)以及LEFT JOIN 将返回左表(表A)中的所有记录,无论这些记录中的任何记录是否与右表(表B)匹配