SQL Server查询:如何使用左外连接

时间:2016-04-26 07:54:34

标签: sql sql-server

我有这个SQL查询:

SELECT 
    COALESCE(a.U, '') AS U, 
    COALESCE(a.N, '') AS N,
    COALESCE (a.J, '')AS J,
    DATENAME(mm, a.P) AS Month,
    DATENAME(yyyy, a.P) AS Year,
    COALESCE(SUM(a.T), 0)  AS Total,
    COALESCE(SUM(b.Pa), 0) AS Cr,
    COALESCE(SUM(a.T), 0) - COALESCE(SUM(b.Pa), 0) AS TPa    
FROM 
    t1 AS a
LEFT OUTER JOIN
    (SELECT 
         U, N, SUM(Cr)
     FROM
         t2 
     WHERE 
         U IS NOT NUll AND N IS NOT NULL
    GROUP BY 
         U, N) AS b ON a.U = b.U AND a.N = b.N
WHERE 
    a.L IS NOT NULL
GROUP BY 
    a.U, a.N, a.J,
    DATENAME(mm, a.P), DATENAME(yyyy, a.P)
ORDER BY 
    Month, Year DESC 

并且此查询产生以下输出:

+----+-------+---+--------+-------+---------+------+--------+
| U  | N     | J |  Month | Year  | Total   |  Cr  |  Tpa   |
+----+-------+---+--------+-------+---------+------+--------+
| 2B | Mark  | a | April  | 2016  | 1500    |  0   | 1500   |
| 2D | Jhon  | b | April  | 2016  | 100     | 4300 | -4200  |
| 2D | Jhon  | a | April  | 2016  | 2000    | 4300 | -2300  |
| 3A | Van   | a | April  | 2016  | 1500    | 7000 | -5500  |
| 2D | Jhon  | a | May    | 2016  | 500     | 4300 | -3800  |
| 3A | Van   | a | May    | 2016  | 1200    | 7000 | -5800  |
+----+-------+---+--------+-------+---------+------+--------+

如果我想生成此输出,那么SQL查询怎么样:

+----+-------+---+--------+-------+---------+------+--------+-------+
| U  | N     | J |  Month | Year  | Total   |  Cr  |  Tpa   | R     |
+----+-------+---+--------+-------+---------+------+--------+-------+
| 2B | Mark  | a | April  | 2016  | 1500    |  0   |  0     | 1500  |
| 2D | Jhon  | b | April  | 2016  | 100     | 4300 | -4200  |  0    |
| 2D | Jhon  | a | April  | 2016  | 2000    | 4200 | -2200  |  0    |
| 3A | Van   | a | April  | 2016  | 1500    | 7000 | -5500  |  0    |
| 2D | Jhon  | a | May    | 2016  | 500     | 2200 | -1700  | -1700 |
| 3A | Van   | a | May    | 2016  | 1200    | 5500 | -4300  | -4300 |
+----+-------+---+--------+-------+---------+------+--------+-------+

首先,(关注表行1,2,4)c列值是从查询行12-16获得的。然后在表格第3行(表格第3行有U和与表格第2行相同的N)中,从绝对值中获取c的值:

来自Total(第2行)-Cr(第2行)的

。换句话说,从ABS(Tpa)获得的C列,其先前具有U和相同的N(U和N的组)。

C柱是从ABS(Tpa)获得的,其先前具有U和相同的N(U和N的组)。

列Tpa中的值从列Total-Cr获得。 如果Total-Cr> 0,则Tpa = 0且R = Total-Cr但如果Total-Cr <= 0,则Tpa = Total-Cr且R列为R = 0.

表格行5和6中的R值是Total-Cr的结果。如果表行是表中的最后一行(按U和N分组),则会出现这种情况。

1 个答案:

答案 0 :(得分:0)

根据我的理解,这种类型的任务可以通过LAG / LEAD等分析函数轻松解决,并使用SUM(...)计算运行总计(PARTITION BY ... ORDER BY ...)。

不幸的是,这些选项仅从SQL Server 2012开始提供。所以我尝试进行更复杂的查询,但这应该在早期版本上运行(在2008年尝试过)。

这是查询。

我在公用表表达式(CTE)t1,t2中生成了值。

T3主要模仿您的查询。只需添加row_number()即可唯一标识组内的行,并查找组中的最后一条记录。

最后,t4有了新的计算方法。

with 
t1 as 
(
    select '2B' as U, 'Mark' as N, 'a' as J, '2016-04-01' as P, 1500 as T, 1 as L union all 
    select '2D' as U, 'Jhon' as N, 'b' as J, '2016-04-01' as P, 100 as T, 1 as L union all 
    select '2D' as U, 'Jhon' as N, 'a' as J, '2016-04-04' as P, 2000 as T, 1 as L union all 
    select '2D' as U, 'Jhon' as N, 'a' as J, '2016-05-05' as P, 500 as T, 1 as L union all 
    select '3A' as U, 'Van' as N, 'a' as J, '2016-04-05' as P, 1500 as T, 1 as L union all 
    select '3A' as U, 'Van' as N, 'a' as J, '2016-05-05' as P, 1200 as T, 1 as L
),

t2 as 
(
    select '2B' as U,'Mark' as N, 0 as Cr union all
    select '2D' as U,'Jhon' as N, 4300 as Cr union all
    select '3A' as U,'Van' as N, 7000 as Cr
),

t3 as 
(
    SELECT 
        COALESCE(a.U, '') AS U, 
        COALESCE(a.N, '') AS N,
        COALESCE (a.J, '')AS J,
        DATENAME(mm, a.P) AS Month,
        DATENAME(yyyy, a.P) AS Year,
        COALESCE(SUM(a.T), 0)  AS Total,
        COALESCE(SUM(b.Pa), 0) AS Cr,
        --COALESCE(SUM(a.T), 0) - COALESCE(SUM(b.Pa), 0) AS TPa, 
        row_number() over (partition by a.U, a.N order by J desc, DATENAME(mm, a.P)) rn,
        row_number() over (partition by a.U, a.N order by J , DATENAME(mm, a.P) desc) rn_last
    FROM 
        t1 AS a
    LEFT OUTER JOIN
        (SELECT 
             U, N, SUM(Cr) as Pa
         FROM
             t2 
         WHERE 
             U IS NOT NUll AND N IS NOT NULL
        GROUP BY 
             U, N) AS b ON a.U = b.U AND a.N = b.N
    WHERE 
        a.L IS NOT NULL
    GROUP BY 
        a.U, a.N, a.J,
        DATENAME(mm, a.P), DATENAME(yyyy, a.P)
)

,t4 as (
    select cte1.*
    ,sum(cte2.Total) Cum_Total -- running total
    ,cte1.Cr - sum(cte2.Total) as Cr_Next
    from t3 cte1
    inner join t3 cte2 on cte1.U = cte2.U and cte1.N = cte2.N and cte1.rn >= cte2.rn
    group by 
    cte1.U, cte1.N, cte1.J, cte1.Month, cte1.Year, cte1.Total, cte1.Cr, cte1.rn, cte1.rn_last
) 

select U,N,J,Month,Year,Total,Cr_New as Cr,
case when Total - Cr_New > 0 then 0 else Total - Cr_New end as Tpa,
case when rn_last = 1 then Total - Cr_New else 0 end R
from
(
    select cte1.* 
    , case when cte1.rn =1 then cte1.Cr else cte2.Cr_Next end as Cr_New
    from t4 as cte1
    left join t4 cte2 on cte1.U = cte2.U and cte1.N = cte2.N and cte1.rn = cte2.rn +1
) t
order by 1,2,3 desc

根据需要生成准确的结果。