2017-10-26 21 views
0

#1 TABLE1SQL ServerのCTEランニングバランス

idno | amount 
------------- 
1 | 700 
2 | 500 

#テーブル2

idno | amount1 | amount2 | amount3 | acctno 
------------------------------------------ 
1 | 100  | 200  | 300  | 001 
1 | 100  | 200  | 300  | 002 
2 | 100  | 200  | 300  | 001 

何が起こるしたいことは表1のamount1にtable2のから量を分配することで、AMOUNT2、amount3残りの残高を得て、次の行に適用します。私はCTEを使用しようとしましたが、実行中の残高を次の行に渡すことに固執しました。

問合せ:

Declare @table2 TABLE (idno varchar(max), amount1 decimal,amount2 
decimal,amount3 decimal,acctno varchar(max)) 
INSERT INTO @table2 VALUES 
('1',100,200,300,'001'), 
('1',100,200,300,'002'), 
('2',100,200,300,'001') 
Declare @table1 TABLE (idno varchar(max), amount decimal) 
INSERT INTO @table1 VALUES 
('1',700), 
('2',500); 
WITH due AS (SELECT a.idno,a.amount,b.acctno,b.amount1,b.amount2,b.amount3 
       from @table1 a left join @table2 b on a.idno = b.idno), 
     payment AS (SELECT *,case when amount-amount1<0 then amount 
       else amount1 end as amount1pay 
       ,case when amount-amount1<=0 then 0 
       when amount-amount1-amount2 <0 then amount-amount1 
       else amount2 end as amount2pay , 
       case when amount-amount1-amount2<=0 then 0 
       when amount-amount1-amount2-amount3<0 
       then amount-amount1-amount2 else amount3 end as amount3pay 
       FROM due), 
     payment2 AS (SELECT SUM(amount-amount1pay-amount2pay-amount3pay) 
        OVER (PARTITION BY idno ORDER BY acctno 
      ROWS UNBOUNDED PRECEDING ) as balance,* FROM payment) 

select * from payment2 

現在の結果

balance | idno | amount | acctno | amount1 | amount2 | amount3 | amount1pay | amount2pay | amount3pay 
--------------------------------------------------------------------------------------------------------- 
    100 | 1 | 200 | 001 |  100 |  200 | 300 | 100  | 200  | 300 
    200 | 1 | 200 | 002 |  100 |  200 | 300 | 100  | 200  | 300 
    0 | 2 | 500 | 001 |  100 |  200 | 300 | 100  | 200  | 200 

期待される結果

balance | idno | amount | acctno | amount1 | amount2 | amount3 | amount1pay | amount2pay | amount3pay 
--------------------------------------------------------------------------------------------------------- 
    100 | 1 | 200 | 001 |  100 |  200 | 300 | 100  | 200  | 300 
    100 | 1 | 200 | 002 |  100 |  200 | 300 | 100  |  0  |  0 
    0 | 2 | 500 | 001 |  100 |  200 | 300 | 100  | 200  | 200 
+0

ここで適用しようとしているルールは、現在、非常に不明です。達成しようとしていることの詳細を追加してください。 – iamdave

答えて

1

これはと思われます非常に混乱しています。ここではさまざまなことが起こっています。私はあなたがこのお金をどのように分配しているかについての「ルール」をすべて理解しているとは思えませんが、このクエリは期待される結果を生み出します(実際には少し異なりますが、 "最初の2つの行の量は" 700 "でなければなりません)?

私の結果は
WITH Base AS (
    SELECT 
     t1.idno, 
     t2.acctno, 
     t1.amount, 
     t2.amount1, 
     t2.amount2, 
     t2.amount3, 
     ROW_NUMBER() OVER (ORDER BY t1.idno, t2.acctno) AS row_id 
    FROM 
     @table1 t1 
     INNER JOIN @table2 t2 ON t1.idno = t2.idno), 
RunningBalance AS (
    SELECT 
     *, 
     CASE WHEN amount > amount1 + amount2 + amount3 THEN amount - amount1 - amount2 - amount3 ELSE 0 END AS new_balance 
    FROM 
     Base), 
NewIdno AS (
    SELECT 
     idno, 
     MIN(row_id) AS first_row_id 
    FROM 
     Base 
    GROUP BY 
     idno), 
NewBalance AS (
    SELECT 
     n.first_row_id AS row_id, 
     b.amount 
    FROM 
     NewIdno n 
     INNER JOIN Base b ON b.row_id = n.first_row_id), 
Amount1 AS (
    SELECT 
     b.row_id, 
     rb1.new_balance AS balance, 
     b.idno, 
     b.amount, 
     b.acctno, 
     b.amount1, 
     b.amount2, 
     b.amount3, 
     CASE WHEN ISNULL(n.amount, rb2.new_balance) >= b.amount1 THEN b.amount1 ELSE b.amount1 - ISNULL(n.amount, rb2.new_balance) END AS pay_amount1, 
     ISNULL(n.amount, rb2.new_balance) - b.amount1 AS carried_forward_1 
    FROM 
     Base b 
     INNER JOIN RunningBalance rb1 ON rb1.row_id = b.row_id 
     LEFT JOIN RunningBalance rb2 ON rb2.row_id = b.row_id - 1 
     LEFT JOIN NewBalance n ON n.row_id = b.row_id), 
Amount2 AS (
    SELECT 
     *, 
     CASE WHEN carried_forward_1 >= amount2 THEN amount2 ELSE carried_forward_1 END AS pay_amount2, 
     carried_forward_1 - CASE WHEN carried_forward_1 >= amount2 THEN amount2 ELSE carried_forward_1 END AS carried_forward_2 
    FROM 
     Amount1), 
Amount3 AS (
    SELECT 
     *, 
     CASE WHEN carried_forward_2 >= amount3 THEN amount3 ELSE carried_forward_2 END AS pay_amount3 
FROM 
     Amount2) 
SELECT 
    balance, 
    idno, 
    amount, 
    acctno, 
    amount1, 
    amount2, 
    amount3, 
    pay_amount1, 
    pay_amount2, 
    pay_amount3 
FROM 
    Amount3; 

:IDNO#用

  • あなたが配布する表1の量で始まり、すなわち£700:

    balance idno amount acctno amount1 amount2 amount3 pay_amount1 pay_amount2 pay_amount3 
    100  1  700  001  100  200  300  100   200   300 
    100  1  700  002  100  200  300  100   0   0 
    0  2  500  001  100  200  300  100   200   200 
    

    私が使用していたルールの一部idno#2については1、£500。

  • これは、acctnosによってテーブル2に番号順に割り当てられています。
  • ここには、残っているものがあれば、前のものから残高を繰り越す必要がある複数のacctnosがあります。
  • 新しいIDNOを開始すると、前のIDNから残ったお金を引き継ぐことはできません。

だから、どのように動作しますか?

ステップ1 - これはちょうど私たちが配布する必要がどのくらいの示す二つのテーブルからのベースデータ、および私たちはそれを上に配布している行のデータを注文すると、インデックス(ROW_ID)

を追加します。

idno acctno amount amount1 amount2 amount3 row_id 
1 001 700 100 200 300 1 
1 002 700 100 200 300 2 
2 001 500 100 200 300 3 

ステップ2 - これは、私たちはそれぞれの行全体で使用可能な全体量分布した場合に残っているどのくらいのお金をうまくいくランニングバランス

をワークアウト:

idno acctno amount amount1 amount2 amount3 row_id new_balance 
1 001 700 100 200 300 1 100 
1 002 700 100 200 300 2 100 
2 001 500 100 200 300 3 0 

ステップ3 - (インタールード)私たちは、これは各IDNOのためのちょうど最初のROW_IDである私たちが最初に

にデータを分散される行知っておく必要があります。

idno first_row_id 
1 1 
2 3 

ステップ4 - 少し無駄な、

row_id amount 
1 700 
3 500 
:我々は最後のステップでこれを行っている可能性として

私達はちょうど、それぞれ「第一」の行の上に分配される合計を必要とします3210

ステップ5 - これは適正なランニングバランスを扱う場所です

各ローのルールは、各金額の最初の行にのみ存在する「新しい残高」から始めるというルールです。これが最初の行でない場合は、代わりに実行中の残高を使用しますが、これを前の行から取ります(rb2.row_id = b.row_id - 1)。我々は常にこれらのいずれか一方を持つことになります。

row_id balance idno amount acctno amount1 amount2 amount3 pay_amount1 carried_forward_1 
1 100 1 700 001 100 200 300 100 600 
2 100 1 700 002 100 200 300 100 0 
3 0 2 500 001 100 200 300 100 400 

ので行わ前方には次の行に運ばれるべきものではありません、それはこの中の次の量(額2に実施すべきである何ケース)を配布する。

これはデータセットでは機能しますが、idnoごとに2つ以上の行がある場合は機能しません。 idnoごとに2つ以上の行がある場合は、このシナリオを処理するために別のステージを追加するだけです。

ステップ6 - 私たちは、この金額に割り当てることができます量、およびに繰り越される金額を与え、私たちは前の計算からの繰越額をそれを取るために必要な各量についてフォワード

キャリー次の計算(これは量4がないので量3に対して冗長である)。

+0

こんにちは、私はあなたのcarry_forward_1を少し編集しました。私はcarry_forward_3はamount2の代わりにamount3を使うべきだと思います。結果に満足しましたが、carry_forward_3の値を次の行にどのように渡しましたか教えてください。 –

+0

はい、最後のcarry_forward_3計算は間違っていましたが、冗長でもあります.3番目の値をどこかに置く必要はないため、削除します。また、このスクリプトの動作を詳しく説明する編集を追加します。 –

+0

こんにちは、あなたが指摘したように、私はidnoごとに2つ以上の行を持つことを検討する必要がありました。どうすればいいか、少なくとも私にヒントを教えてください。 –

関連する問題