意外行为 - 在FULL OUTER JOIN中的“join on”字段中获取副本

时间:2012-11-29 15:59:53

标签: sql sql-server-2008 tsql

我正在加入四个视图,以在ReportingMonth上显示A / R,销售,存款等。但是我在几个月内得到重复。向下看,特别是2014年1月,2014年2月,2012年12月。

duplicate months http://i50.tinypic.com/13yp5ph.png

我有什么:

SELECT ISNULL(ISNULL(ISNULL(outf.ReportingMonth, sales.ReportingMonth), dep.ReportingMonth), ar.ReportingMonth) AS ReportingMonth
    ,ar.AR_100_Percent AS EndOfMonthARBalance
    ,ar.AR_85_Percent AS MLOCCeiling
    ,sales.MonthlySales AS Sales
    ,dep.Deposits
    ,outf.Outflow
    ,dep.Deposits + outf.Outflow AS CashPerformance
FROM vCI_MLOC_MONTHLYAR ar
FULL OUTER JOIN vCI_MLOC_MONTHLYSALES sales
ON ar.ReportingMonth = sales.ReportingMonth
FULL OUTER JOIN vCI_MLOC_MONTHLYDEPOSITS dep
ON sales.ReportingMonth = dep.ReportingMonth
FULL OUTER JOIN vCI_MLOC_MONTHLYOUTF outf
ON dep.ReportingMonth = outf.ReportingMonth
GROUP BY outf.ReportingMonth
    ,dep.ReportingMonth
    ,ar.ReportingMonth
    ,sales.ReportingMonth
    ,ar.AR_100_Percent
    ,ar.AR_85_Percent
    ,sales.MonthlySales
    ,dep.Deposits
    ,outf.Outflow

3 个答案:

答案 0 :(得分:2)

执行full outer joins时遇到问题,因为您最终会在关键列中丢失数据。

以下版本使用驱动程序表来获取所有月份,并对该表进行所有连接:

SELECT driver.ReportingMonth
    ,(other fields here)
FROM (select distinct ReportingMonth
      from ((select ReportingMonth
             from vCI_MLOC_MONTHLYAR
            ) union all
            (select ReportingMonth
             from vCI_MLOC_MONTHLYSALES
            ) union all
            (select ReportingMonth
             from vCI_MLOC_MONTHLYDEPOSITS
            ) union all
            (select ReportingMonth
             from vCI_MLOC_MONTHLYOUTF
            )
           ) t
     ) driver
FULL OUTER JOIN vCI_MLOC_MONTHLYAR ar on driver.ReportingMonth = ar.ReportingMonth
FULL OUTER JOIN vCI_MLOC_MONTHLYSALES sales
ON driver.ReportingMonth = sales.ReportingMonth
FULL OUTER JOIN vCI_MLOC_MONTHLYDEPOSITS dep
ON driver.ReportingMonth = dep.ReportingMonth
FULL OUTER JOIN vCI_MLOC_MONTHLYOUTF outf
ON driver.ReportingMonth = outf.ReportingMonth

答案 1 :(得分:1)

使用FULL联接加入4个表(或无关紧要的视图)是很棘手的。在第二次和第三次加入时,您尝试加入的某些列可能是NULL(由于第一个或第二个外部联接)。

这可能是解决问题的方法。将FROM子句替换为:

FROM vCI_MLOC_MONTHLYAR ar
  FULL OUTER JOIN vCI_MLOC_MONTHLYSALES sales
    ON ar.ReportingMonth = sales.ReportingMonth
  FULL OUTER JOIN vCI_MLOC_MONTHLYDEPOSITS dep
    ON COALESCE(ar.ReportingMonth, sales.ReportingMonth) 
       = dep.ReportingMonth
  FULL OUTER JOIN vCI_MLOC_MONTHLYOUTF outf
    ON COALESCE(ar.ReportingMonth, sales.ReportingMonth, dep.ReportingMonth) 
       = outf.ReportingMonth

或与:

FROM 
        vCI_MLOC_MONTHLYAR ar
      FULL OUTER JOIN vCI_MLOC_MONTHLYSALES sales
          ON ar.ReportingMonth = sales.ReportingMonth
  FULL OUTER JOIN 
        vCI_MLOC_MONTHLYDEPOSITS dep
      FULL OUTER JOIN vCI_MLOC_MONTHLYOUTF outf
          ON dep.ReportingMonth = outf.ReportingMonth
    ON COALESCE(ar.ReportingMonth, sales.ReportingMonth)
     = COALESCE(dep.ReportingMonth, out.ReportingMonth) 

另一种解决方案是使用calendar表格和ReportingMonth列,或者如果没有,可以动态创建(类似于@ Gordon的解决方案):

SELECT cal.ReportingMonth
       --- all the other columns do not change
FROM 
    ( SELECT ReportingMonth
      FROM vCI_MLOC_MONTHLYAR ar
    UNION 
      SELECT ReportingMonth
      FROM vCI_MLOC_MONTHLYSALES sales
    UNION 
      SELECT ReportingMonth
      FROM vCI_MLOC_MONTHLYDEPOSITS dep
    UNION 
      SELECT ReportingMonth
      FROM vCI_MLOC_MONTHLYOUTF outf
    ) AS cal
LEFT JOIN
    vCI_MLOC_MONTHLYAR ar
        ON ar   .ReportingMonth = cal.ReportingMonth
LEFT JOIN
    vCI_MLOC_MONTHLYSALES sales
        ON sales.ReportingMonth = cal.ReportingMonth
LEFT JOIN
    vCI_MLOC_MONTHLYDEPOSITS dep
        ON dep  .ReportingMonth = cal.ReportingMonth
LEFT JOIN
    vCI_MLOC_MONTHLYOUTF outf
        ON outf .ReportingMonth = cal.ReportingMonth

答案 2 :(得分:1)

这也有效......

SELECT ReportingMonth
    ,SUM(EndOfMonthARBalance) AS EndOfMonthARBalance
    ,SUM(MLOCCeiling) AS MLOCCeiling
    ,SUM(Sales) AS Sales
    ,SUM(Deposits) AS Deposits
    ,SUM(Outflow) AS Outflow
    ,SUM(Deposits) + SUM(Outflow) AS CashPerformance

FROM(
    SELECT ReportingMonth AS ReportingMonth
         , NULL AS EndOfMonthARBalance
         , NULL AS MLOCCeiling
         , NULL AS Sales
         , NULL AS Deposits
         , Outflow AS Outflow
    FROM vCI_MLOC_MONTHLYOUTF

    UNION ALL
    SELECT ReportingMonth AS ReportingMonth
         , NULL AS EndOfMonthARBalance
         , NULL AS MLOCCeiling
         , MonthlySales AS Sales
         , NULL AS Deposits
         , NULL AS Outflow
    FROM vCI_MLOC_MONTHLYSALES

    UNION ALL
    SELECT ReportingMonth AS ReportingMonth
         , NULL AS EndOfMonthARBalance
         , NULL AS MLOCCeiling
         , NULL AS Sales
         , Deposits AS Deposits
         , NULL AS Outflow
    FROM vCI_MLOC_MONTHLYDEPOSITS

    UNION ALL  
    SELECT ReportingMonth AS ReportingMonth
         , AR_100_Percent AS EndOfMonthARBalance
         , AR_85_Percent AS MLOCCeiling
         , NULL AS Sales
         , NULL AS Deposits
         , NULL AS Outflow
    FROM vCI_MLOC_MONTHLYAR
) AS a    
GROUP BY ReportingMonth