SQL Server-如何删除总和为零的行对

时间:2019-03-05 12:11:39

标签: sql-server

我需要从金额净减为零的表中消除成对的行。结帐只能在BookCode和ISIN的键组合内进行。

这是原始表:

BookCode    ISIN    Reference     Amount
ABCD        111     R1            -30
ABCD        111     R2             30
ABCD        222     R3            -25
ABCD        222     R4            -25
ABCD        222     R5            -25
ABCD        222     R6            -25
ABCD        222     R7             25
EFGH        333     R8            -20
EFGH        333     R9            -20
EFGH        444     R10            40
EFGH        444     R11           -40
IJKL        555     R12           -10

这就是我想留下的。...

ABCD        222     R3            -25
ABCD        222     R4            -25
ABCD        222     R5            -25
IJKL        555     R12           -10

对于

ABCD / 222 

-25行中的哪一行与R7的正值配对都无关紧要。

任何想法都值得赞赏!

3 个答案:

答案 0 :(得分:0)

尝试如下操作,我用row_number将唯一键强加到它上,所以我不确定它是否可以工作,但这似乎是您需要的原理

WITH CTE AS (SELECT row_number() OVER (ORDER BY BookCode) as id, * FROM OrigTab)
DELETE CTE WHERE CTE.id IN 
    (SELECT c1.id FROM 
                    CTE c1 
                    JOIN 
                    CTE c2 
                    ON 
                            c1.bookcode = c2.bookcode and 
                            c1.id != c2.id and 
                            c1.ISIN = c2.ISIN and 
                            c1.amount+c2.amount = 0
    )

或仅查看行

WITH CTE AS (SELECT row_number() OVER (ORDER BY BookCode) as id, * FROM OrigTab)
SELECT * FROM CTE WHERE CTE.id NOT IN 
    (SELECT c1.id FROM 
                    CTE c1 
                    JOIN 
                    CTE c2 
                    ON 
                            c1.bookcode = c2.bookcode and 
                            c1.id != c2.id and 
                            c1.ISIN = c2.ISIN and 
                            c1.amount+c2.amount = 0
    )

答案 1 :(得分:0)

您可以使用NOT EXISTSROW_NUMBER()进行此操作:

IF OBJECT_ID(N'tempdb..#T', 'U') IS NOT NULL DROP TABLE #T;
CREATE TABLE #T (BookCode VARCHAR(4), ISIN INT, Reference VARCHAR(3), Amount INT);
INSERT INTO #T (BookCode, ISIN, Reference, Amount)
VALUES
    ('ABCD', 111, 'R1', -30),
    ('ABCD', 111, 'R2', 30),
    ('ABCD', 222, 'R3', -25),
    ('ABCD', 222, 'R4', -25),
    ('ABCD', 222, 'R5', -25),
    ('ABCD', 222, 'R6', -25),
    ('ABCD', 222, 'R7', 25),
    ('EFGH', 333, 'R8', -20),
    ('EFGH', 333, 'R9', -20),
    ('EFGH', 444, 'R10', 40),
    ('EFGH', 444, 'R11', -40),
    ('IJKL', 555, 'R12', -10);


WITH RankedData AS
(   SELECT  *, RowNumber = ROW_NUMBER() OVER(PARTITION BY BookCode, ISIN, Amount ORDER BY Reference DESC)
    FROM    #T
)
SELECT  BookCode, ISIN, Reference, Amount
FROM    RankedData AS rd
WHERE   NOT EXISTS
        (   SELECT  1
            FROM    RankedData AS rd2
            WHERE   rd2.BookCode = rd.BookCode
            AND     rd2.ISIN = rd.ISIN
            AND     rd2.Amount = -rd.Amount
            AND     rd2.RowNumber = rd.RowNumber
        );

输出

BookCode    ISIN    Reference   Amount  
------------------------------------------------
ABCD        222     R5          -25     
ABCD        222     R4          -25     
ABCD        222     R3          -25     
EFGH        333     R9          -20     
EFGH        333     R8          -20     
IJKL        555     R12         -10     

ROW_NUMBER()函数确保每一行只能用于取消另一行,否则,结果中将没有ABCD的记录。

或者,如果您要删除网记录,而不是仅选择其余记录,则可以使用:

WITH RankedData AS
(   SELECT  *, RowNumber = ROW_NUMBER() OVER(PARTITION BY BookCode, ISIN, Amount ORDER BY Reference DESC)
    FROM    #T
)
DELETE  rd
FROM    RankedData AS rd
WHERE   EXISTS
        (   SELECT  1
            FROM    RankedData AS rd2
            WHERE   rd2.BookCode = rd.BookCode
            AND     rd2.ISIN = rd.ISIN
            AND     rd2.Amount = -rd.Amount
            AND     rd2.RowNumber = rd.RowNumber
        );

SELECT  *
FROM    #T;

答案 2 :(得分:0)

尝试使用PARTITION BYCommon Table Expressions

这是一个示例:

DECLARE @Table TABLE 
(
    BookCode VARCHAR(10),
    ISIN     int,
    Reference  VARCHAR(10),
    Amount INT 
)

INSERT INTO @Table
(
    BookCode,
    ISIN,
    Reference,
    Amount
)
VALUES
  ('ABCD', 111, 'R1', -30)
, ('ABCD', 111, 'R2', 30)
, ('ABCD', 222, 'R3', -25)
, ('ABCD', 222, 'R4', -25)
, ('ABCD', 222, 'R5', -25)
, ('ABCD', 222, 'R6', -25)
, ('ABCD', 222, 'R7', 25)
, ('EFGH', 333, 'R8', -20)
, ('EFGH', 333, 'R9', -20)
, ('EFGH', 444, 'R10', 40)
, ('EFGH', 444, 'R11', -40)
, ('IJKL', 555, 'R12', -10)

和查询:

;WITH ordered AS
(
    SELECT 
      t.BookCode
    , t.ISIN
    , t.Reference
    , t.Amount
    , ROW_NUMBER()  OVER (PARTITION BY t.BookCode, t.ISIN ORDER BY t.Reference) RN
    FROM  @Table t
), Pairs AS (
    SELECT 
       o1.Reference c1
    , o2.Reference c2
    , ROW_NUMBER() OVER (PARTITION BY  o1.Reference ORDER BY o1.Reference) RN
    FROM ordered o1
    INNER JOIN ordered o2       
        ON o1.Amount = -o2.Amount
            AND o1.RN = o1.RN
    WHERE o1.Amount > 0 
)


DELETE FROM t FROM @Table t
WHERE EXISTS (
SELECT * FROM Pairs p WHERE (p.c1 = t.Reference OR p.c2 = t.Reference AND p.RN = 1)
)
SELECT * FROM @Table t

输出:

BookCode    ISIN    Reference   Amount
  ABCD       222       R4        -25
  ABCD       222       R5        -25
  ABCD       222       R6        -25
  EFGH       333       R8        -20
  EFGH       333       R9        -20
  IJKL       555       R12       -10