1

借方貸方解決システムを実装しようとしていますが、セットに基づいたロジックを表現するのに苦労しています。

Orders のテーブルがあるとします。

Id    OrderId     Amount     AdjustmentFlag
 1       1           10.00        0
 2       1           10.00        1
 3       1           10.00        2
 4       2           20.00        1
 5       2           20.00        2
 6       2           20.00        2
 7       3           30.00        1
 8       4           40.00        0
 9       4           40.00        0
10       4           40.00        1
11       5           50.00        0
12       5           50.00        1
13       5           60.00        2
14       5           60.00        1
15       5           60.00        2
16       5           70.00        1

Id一致する「キャンセル済み」フラグがあるかどうかに基づいて、まだ有効な sを選択する必要があります。

0 - Original Order
1 - Cancelled Order
2 - Adjusted Order
  1. Aは、 より優先してaまたは aに1一致します。020
  2. 1一致しない場合、フラグは無視されます。

上記の例を考えると:

  • ID 2 は ID 1 と一致し、ID 3 が残ります。
  • ID 4 は ID 5 または ID 6 のいずれかと一致しますが、両方とは一致しません。
  • ID 7 は無視されます。
  • ID 10 は ID 8 または ID 9 のいずれかと一致しますが、両方とは一致しません。
  • ID 12 は ID 11 と一致します。
  • ID 14 は ID 13 または ID 15 のいずれかと一致しますが、両方とは一致しません。
  • ID 16 は無視されます。

考えられる結果は、[1, 2, 4, 5, 7, 8, 10, 11, 12, 13, 14, 16] (低い ID が優先) または [1, 2, 4, 6, 7, 9, 10、11、12、14、15、16] (ID が大きいほど優先されます)。結果が決定論的である限り、どちらでも機能します。

スクリプトを作成します。

CREATE TABLE [Order]
(
     Id INT IDENTITY NOT NULL PRIMARY KEY
    ,OrderId INT NOT NULL
    ,Amount MONEY NOT NULL
    ,AdjustmentFlag TINYINT NOT NULL
);

INSERT INTO [Order](OrderId, Amount, AdjustmentFlag)
SELECT 1, 10.00, 0
UNION ALL
SELECT 1, 10.00, 1
UNION ALL
SELECT 1, 10.00, 2
UNION ALL
SELECT 2, 20.00, 1
UNION ALL
SELECT 2, 20.00, 2
UNION ALL
SELECT 2, 20.00, 2
UNION ALL
SELECT 3, 30.00, 1
UNION ALL
SELECT 4, 40.00, 0
UNION ALL
SELECT 4, 40.00, 0
UNION ALL
SELECT 4, 40.00, 1
UNION ALL
SELECT 5, 50.00, 0
UNION ALL
SELECT 5, 50.00, 1
UNION ALL
SELECT 5, 60.00, 2
UNION ALL
SELECT 5, 60.00, 1
UNION ALL
SELECT 5, 60.00, 2
UNION ALL
SELECT 5, 70.00, 1

これが私の現在の部分的な解決策です:

WITH Orders AS
(
    SELECT
        Id,
        OrderId,
        Amount,
        AdjustmentFlag,
        EffectiveOrder = ROW_NUMBER() OVER (PARTITION BY OrderId, Amount ORDER BY AdjustmentFlag DESC),
        UnmatchedOrder = CASE WHEN EXISTS(SELECT 1 FROM [Order] uo WHERE uo.OrderId = o.OrderId GROUP BY uo.OrderId HAVING(COUNT(uo.OrderId) = 1)) THEN 1 ELSE 0 END,
        OriginalWithoutAdjustment = CASE WHEN EXISTS(SELECT 1 FROM [Order] uo WHERE uo.OrderId = o.OrderId AND uo.Amount = o.Amount GROUP BY uo.OrderId, uo.Amount HAVING (MAX(uo.AdjustmentFlag) = 1)) THEN 1 ELSE 0 END,
        AdjustmentWithoutOriginal = CASE WHEN EXISTS(SELECT 1 FROM [Order] uo WHERE uo.OrderId = o.OrderId AND uo.Amount = o.Amount GROUP BY uo.OrderId, uo.Amount HAVING (MIN(uo.AdjustmentFlag) = 1)) THEN 1 ELSE 0 END
    FROM [Order] o
)
,MatchedOrders AS
(
    SELECT
        Id
    FROM Orders
    WHERE
    -- Assume AdjustmentFlag = 2 and take everything else
    EffectiveOrder <> 1
    OR
    (
        -- Assume AdjustmentFlag = 2 and there is no Order with AdjustmentFlag = 0
        -- Take everything since the MIN AdjustmentFlag = 1
        AdjustmentWithoutOriginal = 1
        AND EffectiveOrder > 1
    )
    OR
    (
        -- Assume AdjustmentFlag = 1 and there are no other Orders, so ignore it
        AdjustmentFlag = 1
        AND UnmatchedOrder = 1
    )
    OR
    (
        -- We don't care about the orders if they don't have any Amount
        Amount = 0
        AND EffectiveOrder = 1
    )
    AND NOT
    (
        -- We have an Original without any other Orders
        EffectiveOrder = 1
        AND UnmatchedOrder = 1
        AND AdjustmentFlag = 0
    )
)
SELECT
    o.OrderId,
    o.AdjustmentFlag,
    o.Amount,
    o.EffectiveOrder,
    o.UnmatchedOrder,
    Excluded = CASE WHEN mo.Id IS NULL THEN 0 ELSE 1 END
FROM Orders o
LEFT OUTER JOIN MatchedOrders mo
ON o.Id = mo.Id
ORDER BY OrderId, Amount, AdjustmentFlag

結果:

結果

4

1 に答える 1