2017-11-05 16 views
4

ループを使用せずに解決するのは複雑な問題があります。ループを使うとかなり簡単です。しかし、関係のない2つのテーブルとループなしのマッピング

詳細

後は、私はすべての顧客の支払いプランを保存PaymentPlanテーブル..ですセットベースの操作に考えるようにしようとしたときに非常にトリッキーなことを証明しています。 たとえば、顧客が支払う金額と支払日を入力します。

PlanId |PaymentAmount |CustomerId |StartDate 
100 |200.00   |100  |2017-01-01 
200 |100.00   |100  |2017-02-01 
300 |100.00   |100  |2017-03-01 
400 |200.00   |100  |2017-04-01 

それははcustomerId 100のためのすべての支払い計画が含まれている上に、あなたがテーブルで見ることができるように

次私はTransactionと呼ばれるテーブルを持っています。このテーブルには、上記の支払計画のトランザクションが保存されています。

TransId |CustomerId |Amount |TransactionDate |IsReversed 
100  |100  |100.00 |2017-01-01  |0 
200  |100  |100.00 |2017-01-02  |0 
300  |100  |60.00 |2017-01-04  |0 
400  |100  |40.00 |2017-02-02  |0 
500  |100  |300.00 |2017-04-02  |0 
600  |100  |200.00 |2017-04-10  |1 

問題がPaymentPlanTransaction表の間に関係がないということであり、我々はそれがあまりにも複雑だものを作成することはできませんし、システムがモノリシックです。

私はTransPaymentPlanMapping という名前の新しいテーブルを作成しようとしています。このテーブルは、2つのテーブル間のマッピングを次の形式で保存します。 ループを使用したマッピングの作成は難しくありませんが、パフォーマンスは良くないでしょう。私は解決策を解決するための解決策を用意しています。

CustomerId |transId |PlanId |RunningPaidAmount |transDateTime |IsReversed 
100   |100  |100 |100    |2017-01-01  |0 
100   |200  |100 |200    |2017-01-02  |0 
100   |300  |200 |60     |2017-01-04  |0 
100   |400  |200 |100    |2017-02-02  |0 
100   |500  |300 |100    |2017-04-02  |0 
100   |500  |400 |200    |2017-04-02  |0 
100   |600  |400 |-200    |2017-04-10  |1 

マッピングの仕組みは次のとおりです。 2017-01-01顧客に

  1. TransId: 100 になり$100を支払い、このTRANSIDはplanId 100を割り当てられます。どうして?これは一番早い計画 ですので。
  2. 2017-01-02お客様は別のお支払いとして$100を生成し、TransId 200を生成し、再びplanId 100に割り当てます。どうして?それはステップ1で部分的に支払われた だったからです。planId 100の合計金額は$ 200です。
  3. オン2017-01-04お客様は$60を支払い、planId: 200に割り当てられたtransId: 300を生成します。この支払プランは次のラインであるためです。
  4. 2017-02-02お客様はplanId: 200の金額をに残し、planId: 200にマッピングします。
  5. planId: 300 and 400の支払いが遅れていた顧客2017-04-02には$300を支払うことになり、どちらもplanId: 300 and 400になります。この支払いは1 transId: 500を生成します。しかし、マッピングテーブルでは、このイベントはplanId 300 and 400の2つのエントリを作成します。
  6. 最終ステップ! 2017-04-10の顧客カードは、彼が2017-04-02に行った支払いのために低下し、それはただ$200のために低下します。この結果、取引テーブルで逆仕訳が行われました。このトランザクションは、マッピングテーブルの最新エントリにマップされます。マッピングテーブルに示すように、planId:400は-200になりました。

以下は、PaymentPlanテーブルとtransactionテーブルを作成するスクリプトです。

CREATE TABLE #PaymentPlan(PlanId  INT , 
          PaymentAmount NUMERIC(8,2), 
          CustomerId  INT, 
          StartDate  DATETIME) 
INSERT #PaymentPlan( 
     PlanId , 
     PaymentAmount , 
     CustomerId , 
     StartDate) 
VALUES (100, 200.00, 100, '2017-01-01'), 
     (200, 100.00, 100, '2017-02-01'), 
     (300, 100.00, 100, '2017-03-01'), 
     (400, 200.00, 100, '2017-04-01') 


CREATE TABLE #transaction(TransId   INT, 
          CustomerId  INT, 
          Amount   NUMERIC(8,2), 
          TransactionDate DATETIME, 
          IsReversed BIT) 
INSERT #transaction( 
     TransId , 
     CustomerId , 
     Amount , 
     TransactionDate , 
     IsReversed) 
VALUES (100,100,100.00,'2017-01-01',0), 
     (200,100,100.00,'2017-01-02',0), 
     (300,100,60.00 ,'2017-01-04',0), 
     (400,100,40.00, '2017-02-02',0), 
     (500,100,300.00,'2017-04-02',0), 
     (600,100,200.00,'2017-04-10',1) 

SELECT * FROM #PaymentPlan ORDER BY StartDate 
SELECT * FROM #transaction ORDER BY TransactionDate 

Here is a SQL fiddle

本当に私が得ることができる任意の助けに感謝。

+0

SQL Serverのバージョンはどれですか? – gotqn

+0

私はSQL Serverを使用しています。2014 – John

+0

私が考えていたアプローチの1つは、セントンのテーブルに数値テーブルを使用してトランザクションテーブルを分解することでした。次に、分析関数を使用してその表をパーティションに分割し、n個のセントの各パーティションをその合計に基づいて各プランに割り当てます。実際には、最初の例[ここ](http://www.itprotoday.com/software-development/t-sql-feature-request-add-reset-when-clause-)のように、分析合計をリセットする必要があります。私はそれをカーソルなしで動作させることができませんでした。 – meataxe

答えて

1

両方のテーブルの金額を連続した範囲として表示し、重複したものを見つけることは可能です。次のsnippetは、より洗練されたバージョンのベースになる可能性があります。

CREATE TABLE #PaymentPlan(PlanId  INT, 
          PaymentAmount NUMERIC(8, 2), 
          CustomerId INT, 
          StartDate  DATETIME); 
INSERT #PaymentPlan(
     PlanId, 
     PaymentAmount, 
     CustomerId, 
     StartDate) 
VALUES (100, 200.00, 100, '2017-01-01'), 
     (200, 100.00, 100, '2017-02-01'), 
     (300, 100.00, 100, '2017-03-01'), 
     (400, 200.00, 100, '2017-04-01'); 
CREATE TABLE #transaction(TransId   INT, 
          CustomerId  INT, 
          Amount   NUMERIC(8,2), 
          TransactionDate DATETIME, 
          IsReversed  BIT); 
INSERT #transaction( 
     TransId, 
     CustomerId, 
     Amount, 
     TransactionDate, 
     IsReversed) 
VALUES (100,100,100.00,'2017-01-01',0), 
     (200,100,100.00,'2017-01-02',0), 
     (300,100,60.00 ,'2017-01-04',0), 
     (400,100,40.00, '2017-02-02',0), 
     (500,100,200.00,'2017-04-02',0), 
     (600,100,300.00,'2017-04-10',1); 
WITH 
    p AS (
    SELECT *, 
     SUM(PaymentAmount) OVER(PARTITION BY CustomerId ORDER BY StartDate) - PaymentAmount LeftBound, 
     SUM(PaymentAmount) OVER(PARTITION BY CustomerId ORDER BY StartDate) RightBound 
    FROM #PaymentPlan 
), 
    t AS (
    SELECT *, 
     SUM(Amount) OVER(PARTITION BY CustomerId ORDER BY TransactionDate) - Amount LeftBound, 
     SUM(Amount) OVER(PARTITION BY CustomerId ORDER BY TransactionDate) RightBound 
    FROM #transaction 
) 
SELECT 
    t.CustomerId, t.TransId, p.PlanId, 
    p.LeftBound PlanLeftBound, p.RightBound PlanRightBound, 
    t.LeftBound TransLeftBound, t.RightBound TransRightBound, 
    t.TransactionDate transDateTime, t.IsReversed 
FROM p JOIN t 
    ON p.CustomerId = t.CustomerId AND 
    p.LeftBound < t.RightBound AND 
    p.RightBound > t.LeftBound; 
関連する問題