SQL Server 2 Outer Apply's when used together produce same result

m528fe3b  于 4个月前  发布在  其他
关注(0)|答案(1)|浏览(55)

I have a list of transactions where i would like to get associated transactions from the same table. My main query will bring back any transactions after a certain date for my main transaction code 2310.

The 2 Outer Apply's i have i would like to get back the 805 and 809 transactions that have occured withing 10 days of any 2310 transactions from the main query.

SELECT 
        FAT.DateId,
        FAT.EffectiveDateId,
        FAT.TransactionTypeId,
        FAT.Amount,
        FAT.MKey,
        count(e.MKey) [805 Trans],
        sum(e.amount)[805 Amount],
        count(d.Key)[809 trans],
        sum(d.Amount) [809 Amount]

FROM Warehouse.fact.AccountTransaction FAT 

    JOIN warehouse.dim.TransactionType tt 
        ON tt.TransactionTypeId = fat.TransactionTypeId
           AND tt.SrcBaseId = 3
           AND FAT.DateId >= 20221101
           AND tt.TrnCode = 2310
           AND fat.MKey = 1234
          

    Outer APPLY(
            select FAT1.SrcMor97InstId,FAT1.MKey,FAT1.Amount from Warehouse.fact.AccountTransaction fat1 -- // 809
        where FAT1.MKey = 7341096
           AND FAT1.TransactionTypeid = 5986
           AND FAT1.SrcBaseId = 3
        and CONVERT(datetime, convert(char(8),FAT1.EffectiveDateID)) between CONVERT(datetime, convert(char(8),FAT.EffectiveDateID))  and dateadd(DAY,10,CONVERT(datetime, convert(char(8),FAT.EffectiveDateID)))
              group by FAT1.SrcMor97InstId,
                  FAT1.MKey,
                  FAT1.Amount
    ) D

        Outer APPLY(
-- // 805
        Select SrcMor97InstId, MKey, FAT2.amount from Warehouse.fact.AccountTransaction FAT2
        where FAT2.MKey = 7341096
           AND FAT2.TransactionTypeid = 5982
           AND FAT2.SrcBaseId = 3
            and CONVERT(datetime, convert(char(8),FAT2.EffectiveDateID)) between CONVERT(datetime, convert(char(8),FAT.EffectiveDateID))  and dateadd(DAY,10,CONVERT(datetime, convert(char(8),FAT.EffectiveDateID)))
         group by 
                FAT2.SrcMor97InstId,
               FAT2.MKey,
               FAT2.amount
                    ) E

 group by

        FAT.MKey,
        FAT.DateId,
        FAT.EffectiveDateId,
        FAT.TransactionTypeId,
        FAT.Amount

Above is what i have tried to achive this, SrcMor97InstId is the unique instance that i am trying to group on. For my 805 transactions i would expect to see 1 and for 809 transaction i would expect to see 5 but the but for the outcome i would see 5 for both.

When running each outer Apply in isolation the above is what i get but together they return the same result.

hwamh0ep

hwamh0ep1#

The two outer apply s in your query effectively form multiple independent one-to-many joins, which can cause data duplication and inflated aggregated results. For example, if you had 3 matching TransactionTypeid = 5986 rows and 4 matching TransactionTypeid = 5982 rows, the combined joins would yield 12 result rows feeding the group-by. The 5986 rows would be counted 4 times each and the 5982 rows would be counted 3 times each.

The solution is to move the aggregation inside the outer-apply, so that each yields exactly one row of already-aggregated data. (The outer-apply could actually become a cross-apply at that point.)

Try:

SELECT 
        FAT.DateId,
        FAT.EffectiveDateId,
        FAT.TransactionTypeId,
        FAT.Amount,
        FAT.MKey,
        E.[805 Trans],
        E.[805 Amount],
        D.[809 trans],
        D.[809 Amount]
FROM Warehouse.fact.AccountTransaction FAT 
    JOIN warehouse.dim.TransactionType tt 
        ON tt.TransactionTypeId = fat.TransactionTypeId
           AND tt.SrcBaseId = 3
           AND FAT.DateId >= 20221101
           AND tt.TrnCode = 2310
           AND fat.MKey = 1234
    CROSS APPLY (
        select
            count(FAT1.MKey) AS [809 trans],
            sum(FAT1.Amount) AS [809 Amount]
        from Warehouse.fact.AccountTransaction fat1 -- // 809
        where FAT1.MKey = 7341096
           AND FAT1.TransactionTypeid = 5986
           AND FAT1.SrcBaseId = 3
        and CONVERT(datetime, convert(char(8),FAT1.EffectiveDateID)) between CONVERT(datetime, convert(char(8),FAT.EffectiveDateID))  and dateadd(DAY,10,CONVERT(datetime, convert(char(8),FAT.EffectiveDateID)))
        --      group by FAT1.SrcMor97InstId,
        --          FAT1.MKey,
        --          FAT1.Amount
        )
    ) D
    Outer APPLY (
        -- // 805
        select
            count(FAT2.MKey) AS [805 trans],
            sum(FAT1.Amount) AS [805 Amount]
        from Warehouse.fact.AccountTransaction FAT2
        where FAT2.MKey = 7341096
           AND FAT2.TransactionTypeid = 5982
           AND FAT2.SrcBaseId = 3
            and CONVERT(datetime, convert(char(8),FAT2.EffectiveDateID)) between CONVERT(datetime, convert(char(8),FAT.EffectiveDateID))  and dateadd(DAY,10,CONVERT(datetime, convert(char(8),FAT.EffectiveDateID)))
        -- group by 
        --        FAT2.SrcMor97InstId,
        --       FAT2.MKey,
        --       FAT2.amount
    ) E

group by
        FAT.MKey,
        FAT.DateId,
        FAT.EffectiveDateId,
        FAT.TransactionTypeId,
        FAT.Amount

I am unsure what the intended purpose of the inner GROUP BY s. I have tentatively commented them out. It is unusual to see a GROUP BY ...Amount , where that amount is eventually fed into a SUM(Amount) . That can lead to accidental dropping of amounts from the calculation just because they match other amounts.

If the inner group-bys are needed, you can wrap them into a subselect within the cross-apply:

CROSS APPLY (
        SELECT
            count(D.MKey) AS [809 Trans],
            sum(D.amount) AS [809 Amount]
        FROM (
            select FAT1.SrcMor97InstId,FAT1.MKey,FAT1.Amount
            from Warehouse.fact.AccountTransaction fat1 -- // 809
            where FAT1.MKey = 7341096
               AND FAT1.TransactionTypeid = 5986
               AND FAT1.SrcBaseId = 3
               and CONVERT(datetime, convert(char(8),FAT1.EffectiveDateID)) between CONVERT(datetime, convert(char(8),FAT.EffectiveDateID))  and dateadd(DAY,10,CONVERT(datetime, convert(char(8),FAT.EffectiveDateID)))
            group by FAT1.SrcMor97InstId,
                  FAT1.MKey,
                  FAT1.Amount
        ) D
    ) D
    CROSS APPLY (
        SELECT
            count(E.MKey) AS [805 Trans],
            sum(E.amount) AS [805 Amount]
        FROM (
            Select SrcMor97InstId, MKey, FAT2.amount
            from Warehouse.fact.AccountTransaction FAT2
            where FAT2.MKey = 7341096
               AND FAT2.TransactionTypeid = 5982
               AND FAT2.SrcBaseId = 3
               and CONVERT(datetime, convert(char(8),FAT2.EffectiveDateID)) between CONVERT(datetime, convert(char(8),FAT.EffectiveDateID))  and dateadd(DAY,10,CONVERT(datetime, convert(char(8),FAT.EffectiveDateID)))
            group by 
                FAT2.SrcMor97InstId,
                FAT2.MKey,
                FAT2.amount
        ) E
    ) E

I believe you can also combine the two cross-applys by selecting both TransactionTypeid values in the subquery and using conditional aggregation to later separate the values.

CROSS APPLY (
        SELECT
            count(CASE WHEN TransactionTypeid = 5982 THEN D.MKey END) AS [805 Trans],
            sum(CASE WHEN TransactionTypeid = 5982 THEN D.amount END) AS [805 Amount],
            count(CASE WHEN TransactionTypeid = 5986 THEN D.MKey END) AS [809 Trans],
            sum(CASE WHEN TransactionTypeid = 5986 THEN D.amount END) AS [809 Amount]
        FROM (
            select FAT1.TransactionTypeid, FAT1.SrcMor97InstId, FAT1.MKey, FAT1.Amount
            from Warehouse.fact.AccountTransaction FAT1 -- 805/809
            where FAT1.MKey = 7341096
               AND FAT1.TransactionTypeid IN (5982, 5986)
               AND FAT1.SrcBaseId = 3
               and CONVERT(datetime, convert(char(8),FAT1.EffectiveDateID)) between CONVERT(datetime, convert(char(8),FAT.EffectiveDateID))  and dateadd(DAY,10,CONVERT(datetime, convert(char(8),FAT.EffectiveDateID)))
            group by
                  FAT1.TransactionTypeid,
                  FAT1.SrcMor97InstId,
                  FAT1.MKey,
                  FAT1.Amount
        ) D
    ) D

相关问题