1

次の一時テーブルの行と同様の行数が与えられます。

TransactionId | AccountsDocumentLineId | Amount
-------------   ----------------------   ------
52345           12345                    -15.79
52346           12345                    15.79
52347           12345                    -15.79
52348           22222                    -6.34
52349           22222                    6.34
52350           22222                    6.34
52351           22222                    -6.34
52352           22222                    -8.76
52353           22222                    10.49

同じ もので互いに打ち消し合う(合計がゼロになる)AccountsDocumentLineId行を削除し、ペアにできる一致する行がなくなった行だけを残すにはどうすればよいですか?

したがって、上記の例では、TransactionId= 52345または 52347)の行が残されます(-15.7915.79は互いに打ち消し合うため)。

同様に、TransactionId=52352との行52353は残ります(との2つのペアが-6.34互いに6.34打ち消し合うため)。

したがって、次の最終結果が得られます。

TransactionId | AccountsDocumentLineId | Amount
-------------   ----------------------   ------
52347           12345                    -15.79
52352           22222                    -8.76
52353           22222                    10.49

注:目前の問題を簡単に示すために、不要な詳細(列と行を増やして)をすべて削除しました。

私が遊んだいくつかのオプションは次のとおりです。-

  • Amountsのグループ内のすべてのsを合計し、AccountDocumentLineIdどの行がバランスに一致するかを確認しますが、これは最初の例(1行だけが残っている)のみを扱い、2行が残っている必要がある2番目の例は扱いません(したがって1つの値を分割して2つの行を指定するのは簡単ではありません)

  • sのグループ内の各エントリAccountDocumentLineIdを調べ、一致するものが見つかった場合は、両方の対応するものを削除します。SQLでそれを行う方法がわからないが、これはうまくいくと思いますか?

SQLFiddleデモ

更新:Bulatの回答に基づく完全な回答を追加しました。

4

3 に答える 3

1

最初のステップは簡単です

DELETE FROM MYTABLE WHERE AccountsDocumentLineId IN
  (SELECT AccountsDocumentLineId from MYTABLE 
   GROUP BY AccountsDocumentLineId 
   HAVING SUM(Amount) <> 0)

しかし、精度の高いエラーに対処するためにやらなければならないことがあるかもしれません。

それはあなたに不均衡なアカウントだけを残すはずです。そこから、借方を貸方に「割り当てる」ためのストアドプロシージャを作成する必要があります(私は思います)。データサンプルから、トランザクションIDが適切に順序付けられている可能性が高いため、これが役立つはずです。

于 2013-01-25T11:30:51.320 に答える
1

このコードは何度でも実行できます(たとえば、0を超えるレコードに影響する場合)。

WITH Matches AS
(
SELECT t1 = t1. TransactionId, t2 = t2.TransactionId, 
  a1 = t1.Amount, a2 = t2.Amount, t1.AccountsDocumentLineId
FROM  Transactions t1 
    INNER JOIN Transactions t2 
        ON t1.AccountsDocumentLineId = t2.AccountsDocumentLineId
           AND t1.Amount = -t2.Amount 
           AND t1.TransactionId < t2.TransactionId 
)
DELETE FROM Transactions
WHERE EXISTS (
SELECT * FROM Matches m1
WHERE Transactions.TransactionId IN(m1.t1,m1.t2)
  AND NOT EXISTS
 (SELECT * FROM Matches m2
  WHERE  abs(m1.a1) = abs(m2.a1) 
     AND m1.AccountsDocumentLineId = m2.AccountsDocumentLineId
     AND (
         (m2.t1 > m1.t1 AND m2.t2 <= m1.t2)  
      OR (m2.t2 < m1.t2 AND (m2.t1 >= m1.t1))
      OR m2.t1 = m1.t2
     ) 
 )
);
于 2013-01-25T15:42:20.360 に答える
0

ラップされたコードに対するBulatの要求に応えて、ここに(そして他の人の利益のために)それを提出します:

DECLARE 
      @SequenceStart INT = 0,
      @SequenceEnd INT = 10 -- Just to be on the safe side, though unlikely for there to be 10 matching pairs for the same AccountsDocumentLineId

STARTLOOP:
    SET
        @SequenceStart = @SequenceStart+1   
    ;
    WITH Matches AS
    (
        SELECT
            L1 = L1.TransactionId, L2 = L2.TransactionId,
            A1 = L1.Amount, A2 = L2.Amount, L1.AccountsDocumentLineId
        FROM
            #RemainingLedgerEntries L1
            INNER JOIN #RemainingLedgerEntries L2
                ON L1.AccountsDocumentLineId = L2.AccountsDocumentLineId
                AND L1.Amount*-1 = L2.Amount
                AND L1.TransactionId < L2.TransactionId
    )
    DELETE FROM
        #RemainingLedgerEntries
    WHERE
        EXISTS
        (
            SELECT
                *
            FROM
                Matches M1
            WHERE
                #RemainingLedgerEntries.TransactionId IN (M1.L1, M1.L2)
            AND NOT EXISTS
            (
                SELECT
                    *
                FROM
                    Matches M2
                WHERE
                    ABS(M1.A1) = ABS(M2.A1) 
                AND M1.AccountsDocumentLineId = M2.AccountsDocumentLineId
                AND
                (
                    (M2.L1 > M1.L1 AND M2.L2 <= M1.L2)  
                    OR (M2.L2 < M1.L2 AND (M2.L1 >= M1.L1))
                    OR M2.L1 = M1.L2
                ) 
            )
        )

    IF @SequenceStart >= @SequenceEnd
        GOTO ENDTASK

    GOTO STARTLOOP

ENDTASK:
于 2013-01-29T11:12:31.193 に答える