按聚合值删除行

时间:2018-03-21 13:03:10

标签: tsql sql-delete

我有一个包含详细行的表。我们希望从此表中为聚合值进行事务处理。可能存在一种情况,其中一行为正,另一行为负。聚合为0.我想删除这些行。

以下是我的例子:

DECLARE @tmp TABLE ( orderid INT
,                    account INT
,                    vatid   INT
,                    amount  DECIMAL(10,2)
,                    vat     DECIMAL(10,2) )

--test values
INSERT @tmp
VALUES ( 10001, 30500, 47, 175.50,  9.20  )
,      ( 10001, 30501, 47, 2010.60, 18.30 )
,      ( 10001, 30501, 47, 147.65,  8.05  )
,      ( 10001, 30502, 47, 321.15,  18.40 )
,      ( 10001, 30502, 47, 13.50,   0.95  )
,      ( 10001, 30510, 40, 15.00,   0.0   )
,      ( 10001, 30510, 40, -15.00,  0.0   )

--all rows
SELECT * FROM @tmp

--aggregate
  --aggregate for account 30510 is 0
SELECT tmp.orderid    
,      tmp.account    
,      tmp.vatid      
,      SUM(tmp.amount) [totalamount]
,      SUM(tmp.vat)    [totalvat]
FROM @tmp tmp
GROUP BY tmp.orderid
,        tmp.account
,        tmp.vatid

--delete rows with aggregated values 0
DELETE tmp
FROM @tmp tmp 
JOIN (
    SELECT ag.orderid
    ,      ag.account
    ,      ag.vatid
    FROM (
        SELECT tmp.orderid    
        ,      tmp.account    
        ,      tmp.vatid      
        ,      SUM(tmp.amount) [totalamount]
        ,      SUM(tmp.vat)    [totalvat]
        FROM @tmp tmp
        GROUP BY tmp.orderid
        ,        tmp.account
        ,        tmp.vatid
        ) ag
    WHERE ISNULL(ag.totalamount,0) = 0
        AND ISNULL(ag.totalvat,0) = 0
    )         tmp2
    ON tmp2.orderid = tmp.orderid
    AND tmp2.account = tmp.account
    AND tmp2.vatid = tmp.vatid

--check rows
SELECT * FROM @tmp

我的代码工作并删除聚合值为0的行。

但它看起来并不优雅。有没有更好的方法来实现相同的结果?

Greetings Reto

3 个答案:

答案 0 :(得分:2)

使用window function

delete tt
from (  select sum(t.vat)    over (partition by t.orderid, t.account, t.vatid) as sumVat
             , sum(t.amount) over (partition by t.orderid, t.account, t.vatid) as sumAmt
          from @tmp t 
     ) tt 
where isnull(tt.sumAmt, 0) = 0 
  and isnull(tt.sumVat, 0) = 0

答案 1 :(得分:1)

试试这个

  

在较早阶段使用HAVING而不是在后期使用WHERE。因此,查询将在分组级别过滤掉不需要的记录,并且仍会产生相同的结果。

--delete rows with aggregated values 0
DELETE tmp
FROM @tmp tmp 
JOIN (
    SELECT ag.orderid
    ,      ag.account
    ,      ag.vatid
    FROM (
        SELECT tmp.orderid    
        ,      tmp.account    
        ,      tmp.vatid      
        -- Removed unwanted aggregates from select clause here
        FROM @tmp tmp
        GROUP BY tmp.orderid
        ,        tmp.account
        ,        tmp.vatid
        HAVING SUM(tmp.amount) = 0 -- This line is updated
        AND SUM(tmp.vat) = 0 -- This line is updated
        ) ag
        -- Removed WHERE clause from here and added HAVING above
    )         tmp2
    ON tmp2.orderid = tmp.orderid
    AND tmp2.account = tmp.account
    AND tmp2.vatid = tmp.vatid

答案 2 :(得分:1)

我会使用公用表表达式来仅获取需要删除的行,然后使用内部联接从表中删除到按列分组的cte:

;WITH CTE AS
(
    SELECT tmp.orderid    
    ,      tmp.account    
    ,      tmp.vatid      
    FROM @tmp tmp
    GROUP BY tmp.orderid
    ,        tmp.account
    ,        tmp.vatid
    HAVING SUM(tmp.amount) = 0
    AND SUM(tmp.vat) = 0
)

DELETE t
FROM @Tmp as t
JOIN CTE ON t.orderid = cte.orderid
        AND t.account = cte.account
        AND t.vatid = cte.vatid

Extend prestashop webservice resource