1

私はいくつかのデータ、実際の例を持っています。データを特定の方法で表示するために、必要な結果を得るためにデータを操作しなければならないような方法でデータが保存されます。基本的に、請求書には 2 つの異なるタイプがあります。注文が処理される前に金額が請求される事前請求書 (P)。出荷後に残金が請求される標準請求書 (I)。通常の状況下では、標準請求書から請求書前の金額が差し引かれると予想されます。たとえば、請求前請求書が 2 ドルで注文が 10 ドルの場合、標準請求書は 8 ドルになります。ただし、標準の請求書は $10 として保存されます。

以下は完全に操作可能なクエリです (そのクエリは操作可能です! これは罠です!) データを入力し、必要な結果を返します。目標は、請求額を取得し、それが事前請求書の場合はその金額を返すことです。ただし、それが標準の請求書の場合は、事前請求書の値を「使い果たし」、新しい金額、最小ゼロを返します。事前請求書は任意の金額になる可能性があり、技術的にはいつでも必要になる可能性があるため、6 つのシナリオを含めました。

これに関するご支援をいただければ幸いです。UNBOUNDED PRECEDING タイプのものを含むいくつかのウィンドウ関数を試しましたが、再帰的で無限ループに入る必要があるように常に思えました。したがって、以下の私のブルートフォースアプローチ。

DECLARE @PData TABLE (
     CustNum        INT
    ,TransNum       INT
    ,InvType        NVARCHAR(1)
    ,InvAmt         DECIMAL(5,2)
    ,CRank          INT
    ,TRank          INT
    ,ModInvAmt      DECIMAL(5,2)
    )

INSERT INTO @PData (
     CustNum
    ,TransNum
    ,InvType
    ,InvAmt
    )

    VALUES
     (124, 1,'P',2)
    ,(124, 2,'I',10)
    ,(124, 3,'I',10)
    ,(153, 4,'I',10)
    ,(153, 5,'P',2)
    ,(153, 6,'I',10)
    ,(324, 7,'I',10)
    ,(324, 8,'I',10)
    ,(324, 9,'P',2)
    ,(441,10,'P',12)
    ,(441,11,'I',10)
    ,(441,12,'I',10)
    ,(455,13,'I',10)
    ,(455,14,'P',12)
    ,(455,15,'I',10)
    ,(667,16,'I',10)
    ,(667,17,'I',10)
    ,(667,18,'P',12)

UPDATE pd1
    SET CRank = pd2.CDR
        FROM @PData pd1
            JOIN (SELECT CustNum, TransNum, DENSE_RANK() OVER (ORDER BY CustNum) AS CDR
                    FROM @PData) pd2
                ON pd1.TransNum = pd2.TransNum

UPDATE pd1
    SET TRank = pd2.TDR
        FROM @PData pd1
            JOIN (SELECT CustNum, TransNum, DENSE_RANK() OVER (PARTITION BY CustNum ORDER BY TransNum) AS TDR
                    FROM @PData) pd2
                ON pd1.TransNum = pd2.TransNum

DECLARE  @Counter1      INT
        ,@Counter2      INT
        ,@CBal          DECIMAL(5,2)
        ,@TNum          INT
        ,@IAmt          DECIMAL(5,2)

SET @Counter1 = 0

WHILE @Counter1 < (SELECT MAX(CRank) FROM @PData)
    BEGIN
        SET @Counter1 += 1
        SET @CBal = 0
        SET @Counter2 = 0
            WHILE @Counter2 < (SELECT MAX(TRank) FROM @PData WHERE CRank = @Counter1)
                BEGIN
                    SET @Counter2 += 1
                    SET @TNum = (SELECT TransNum FROM @PData WHERE CRank = @Counter1 AND TRank = @Counter2)
                    SET @IAmt = (SELECT InvAmt FROM @PData WHERE TransNum = @TNum)
                    IF (SELECT InvType FROM @PData WHERE TransNum = @TNum) = 'P'
                        BEGIN
                            UPDATE @PData SET ModInvAmt = @IAmt WHERE TransNum = @TNum
                            SET @CBal += -@IAmt 
                        END
                    ELSE
                        BEGIN
                            UPDATE @PData SET ModInvAmt = (ABS(@IAmt+@CBal)+(@IAmt+@CBal))/2 -- MINIMUM = 0
                                 WHERE TransNum = @TNum
                            SET @CBal += (@IAmt - (ABS(@IAmt+@CBal)+(@IAmt+@CBal))/2)
                        END                 
                END
    END

SELECT   CustNum
        ,TransNum
        ,InvType
        ,InvAmt
        ,ModInvAmt
 FROM @PData

ここに私が得る結果があります: ここに画像の説明を入力

通常、元の請求書の金額は報告しませんが、新しい請求書の金額だけを報告しますが、どのように変化したかがより明確になるように、ここに記載しました。

 CustNum TransNum InvType InvAmt  ModInvAmt
 124      1         P     2.00      2.00
 124      2         I    10.00      8.00
 124      3         I    10.00     10.00
 153      4         I    10.00     10.00
 153      5         P     2.00      2.00
 153      6         I    10.00      8.00
 324      7         I    10.00     10.00
 324      8         I    10.00     10.00
 324      9         P     2.00      2.00
 441     10         P    12.00     12.00
 441     11         I    10.00      0.00
 441     12         I    10.00      8.00
 455     13         I    10.00     10.00
 455     14         P    12.00     12.00
 455     15         I    10.00      0.00
 667     16         I    10.00     10.00
 667     17         I    10.00     10.00
 667     18         P    12.00     12.00
4

1 に答える 1