(可能)复杂使用聚合连接四个表

时间:2014-02-03 13:33:13

标签: sql sql-server join

我正在尝试将“主”表Account加入三个相关表,并对每个表应用一些WHERE标准。

这是我到目前为止的查询:

SELECT Account.Name
     , AnnAccs.PeriodEnd AS AnnAccsPeriodEnd
     , AnnAccs.LastPeriod AS AnnAccsLastPeriod
     , CorpTax.PeriodEnd AS CorpTaxPeriodEnd
     , CorpTax.LastPeriod AS CorpTaxLastPeriod
     , SelfAss.PeriodEnd AS SAPeriodEnd
     , SelfAss.LastPeriod AS SALastPeriod
  FROM dbo.Account
  LEFT JOIN (SELECT MAX(new_corporationtaxactivity.new_PeriodEnd) AS PeriodEnd
                  , new_corporationtaxactivity.new_LastPeriod AS LastPeriod
                  , new_CorporationTaxActivityId AS AccId
               from new_corporationtaxactivity 
              GROUP BY 
                    new_CorporationTaxActivityId
                  , new_corporationtaxactivity.new_LastPeriod
            ) AS CorpTax 

    ON CorpTax.AccId = Account.AccountId 
  LEFT JOIN (SELECT MAX(new_annualaccountsactivity.new_PeriodEnd) AS PeriodEnd
                  , new_annualaccountsactivity.new_LastPeriod AS LastPeriod
                  , new_AnnualAccountsActivityId AS AccId 
               from new_annualaccountsactivity 
              GROUP BY 
                    new_AnnualAccountsActivityId
                  , new_annualaccountsactivity.new_LastPeriod
            ) AS AnnAccs 
    ON AnnAccs.AccId = Account.AccountId
  LEFT JOIN (SELECT MAX(new_selfassessmentactivity.new_PeriodEnd) AS PeriodEnd
                  , new_selfassessmentactivity.new_LastPeriod AS LastPeriod
                  , new_SelfAssessmentActivityId AS AccId 
               from new_selfassessmentactivity 
              GROUP BY 
                    new_SelfAssessmentActivityId
                  , new_selfassessmentactivity.new_LastPeriod
            ) As SelfAss 
    ON SelfAss.AccId = Account.AccountId
 WHERE (    Account.new_ClientStatus = '100000000' 
         OR Account.new_ClientStatus = '100000001')
   AND (    AnnAccs.LastPeriod = '1' 
         OR CorpTax.LastPeriod = '1' 
         OR SelfAss.LastPeriod = '1')

帐户表格为1:*,包含三个相关表格,我想执行以下操作:对于每个帐户,检查每个相关表格中的最新/最新活动(无论是年度帐户,公司税)或者自我评估,其中可能没有,被标记为“上一期”。

例如,一个帐户可能有自我评估活动(即自我评估视图/表中的一行)而没有其他相关活动,所以我希望看到类似的内容:

AccName  |  AnnAccsPeriodEnd  |  AnnAccsLastPeriod  |  CorpTaxPeriodEnd  |  CorpTaxLastPeriod  |  SAPeriodEnd  |  SALastPeriod
AccA     |              null  |               null  |              null  |               null  |   01/01/2014  |          true

同样,它的年度帐户活动可能不为空,但仍未标记为“LastPeriod”:

AccName  |  AnnAccsPeriodEnd  |  AnnAccsLastPeriod  |  CorpTaxPeriodEnd  |  CorpTaxLastPeriod  |  SAPeriodEnd  |  SALastPeriod
AccA     |        01/01/2014  |              false  |              null  |               null  |   01/01/2014  |          true

因此,对于其中一个活动被标记为“LastPeriod”的每个帐户,我只想要一行(一个帐户,可能1-2个相关表的列为null,至少一个总是有数据,其中LastPeriod =真)。

上面的查询给出了看起来几乎看起来像交叉或完整联接的奇怪结果,因此每个帐户将产生3-4行。例如。

在过去的几天里,我一直在为此烦恼 - 任何帮助都会非常感激!

如果我能更详细地改进问题,请告诉我!

(感谢您的编辑!)

1 个答案:

答案 0 :(得分:1)

如果您只想要最新一行,可以将每个子查询转换为APPLY

SELECT  Account.Name, 
        AnnAccs.PeriodEnd AS AnnAccsPeriodEnd, 
        AnnAccs.LastPeriod AS AnnAccsLastPeriod,
        CorpTax.PeriodEnd AS CorpTaxPeriodEnd, 
        CorpTax.LastPeriod AS CorpTaxLastPeriod,
        SelfAss.PeriodEnd AS SAPeriodEnd, 
        SelfAss.LastPeriod AS SALastPeriod
FROM    dbo.Account 
        OUTER APPLY
        (   SELECT  TOP 1
                    ca.new_PeriodEnd AS PeriodEnd, 
                    ca.new_LastPeriod AS LastPeriod, 
                    new_CorporationTaxActivityId AS AccId 
            FROM    new_corporationtaxactivity ca
            WHERE   ca.AccId = Account.AccountId 
            ORDER BY ca.new_PeriodEnd DESC
        ) AS CorpTax 
        OUTER APPLY
        (   SELECT  TOP 1 aa.new_PeriodEnd AS PeriodEnd, 
                    aa.new_LastPeriod AS LastPeriod, 
                    aa.new_AnnualAccountsActivityId AS AccId 
            FROM    new_annualaccountsactivity aa
            WHERE   aa.new_AnnualAccountsActivityId = Account.AccountId 
            ORDER BY aa.new_PeriodEnd DESC
        ) AS AnnAccs 
        OUTER APPLY
        (   SELECT  TOP 1 sa.new_PeriodEnd AS PeriodEnd, 
                    sa.new_LastPeriod AS LastPeriod, 
                    sa.new_SelfAssessmentActivityId AS AccId 
            FROM    new_selfassessmentactivity sa
            WHERE   sa.new_SelfAssessmentActivityId = Account.AccountId
            ORDER BY sa.new_PeriodEnd DESC
        ) As SelfAss 
WHERE   (Account.new_ClientStatus = '100000000' OR Account.new_ClientStatus = '100000001')
AND     (AnnAccs.LastPeriod = '1' OR CorpTax.LastPeriod = '1' OR SelfAss.LastPeriod = '1')

或者您可以向每个子查询添加ROW_NUMBER()并将其限制为最高结果(RowNum = 1):

SELECT  Account.Name, 
        AnnAccs.PeriodEnd AS AnnAccsPeriodEnd, 
        AnnAccs.LastPeriod AS AnnAccsLastPeriod,
        CorpTax.PeriodEnd AS CorpTaxPeriodEnd, 
        CorpTax.LastPeriod AS CorpTaxLastPeriod,
        SelfAss.PeriodEnd AS SAPeriodEnd, 
        SelfAss.LastPeriod AS SALastPeriod
FROM    dbo.Account 
        LEFT JOIN 
        (   SELECT  ca.new_PeriodEnd AS PeriodEnd, 
                    ca.new_LastPeriod AS LastPeriod, 
                    ca.new_CorporationTaxActivityId AS AccId,
                    ROW_NUMBER() OVER(PARTITION BY ca.new_CorporationTaxActivityId ORDER BY ca.new_PeriodEnd DESC) AS RowNum
            FROM    new_corporationtaxactivity  ca
        ) AS CorpTax 
            ON CorpTax.AccId = Account.AccountId 
            AND CorpTax.RowNum = 1
        LEFT JOIN 
        (   SELECT  aa.new_PeriodEnd AS PeriodEnd, 
                    aa.new_LastPeriod AS LastPeriod, 
                    aa.new_AnnualAccountsActivityId AS AccId,
                    ROW_NUMBER() OVER(PARTITION BY aa.new_AnnualAccountsActivityId ORDER BY aa.new_PeriodEnd DESC) AS RowNum
            FROM    new_annualaccountsactivity aa
        ) AS AnnAccs 
            ON AnnAccs.AccId = Account.AccountId
            AND AnnAccs.RowNum = 1
        LEFT JOIN 
        (   SELECT  sa.new_PeriodEnd AS PeriodEnd, 
                    sa.new_LastPeriod AS LastPeriod, 
                    sa.new_SelfAssessmentActivityId AS AccId,
                    ROW_NUMBER() OVER(PARTITION BY sa.new_SelfAssessmentActivityId ORDER BY sa.new_PeriodEnd DESC) AS RowNum
            FROM    new_selfassessmentactivity sa
        ) As SelfAss 
            ON SelfAss.AccId = Account.AccountId
            AND SelfAss.RowNum = 1
WHERE   (Account.new_ClientStatus = '100000000' OR Account.new_ClientStatus = '100000001')
AND     (AnnAccs.LastPeriod = '1' OR CorpTax.LastPeriod = '1' OR SelfAss.LastPeriod = '1');