T-SQL Split Rows? - PullRequest
       28

T-SQL Split Rows?

0 голосов
/ 14 декабря 2011

У меня есть набор результатов ниже

Rank    cardID      DespatchValue   Spend   SumSpend    Spendtype
0       468612      500                0          0         Despatch
1       468612      500             -8500       -8500       Topup
2       468612      500            -11500       -20000      Topup
3       468612      500             -3500       -23500      Topup

Как вы видите, каждый расход добавляется к сумме расходов (через рекурсивный CTE), которой я доволен.

Однако логика должна работать таким образом

  • Стоимость отправки до первоначальных затрат = Баланс типа расходов
  • Что-нибудь после этого = Пополнить

Итак,

Хотелось бы увидеть:

Rank    cardID  DespatchValue   Spend   SumSpend    Spendtype
0       468612  500               0        0        Despatch
?       468612  500             -500    -500        Balance
1       468612  500             -8000   -8500       Topup
2       468612  500             -11500  -20000      Topup
3       468612  500             -3500   -23500      Topup

Есть идеи, как этого добиться?

1 Ответ

1 голос
/ 23 декабря 2011

Чтобы разделить строку, вам нужно добавить еще два предложения UNION к вашему CTE. Большинство рекурсивных CTE имеют «якорь» и рекурсивный бит. Вам нужно будет расширить, как работает этот рекурсивный бит. Во-первых, вы определяете, когда следует превзойти «номинальный» случай, который для вас - когда баланс переходит от положительного итога к отрицательному. В вашем случае это "DespatchValue + SumSpend".

Следующими двумя терминами будут ваши «разделенные» строки. Использование инверсии любого условия, указанного выше (т. Е. Вернуть только строки поверх этого «специального» условия). Первый UNION будет записью "BALANCE", сводя ее к нулю. Второй - это остаток того, что осталось.

Вот то, что я придумал - обратите внимание, что я добавил столбец «subid», чтобы указать «баланс» (и предотвратить повторения в последующей рекурсии). Я также добавил DespatchBalance, предполагая, что это действительно то, что вы проверяете. Если не учитывать конкретику, общий формат должен быть хорошим:

declare @txn as table (
    id int, 
    cardID int, 
    DespatchValue int, 
    Spend int
    --SumSpend int, 
    --Spendtype varchar(50)
)

insert into @txn
                    select 0, 468612, 500, 0--, 0, 'Despatch'
union all select 1, 468612, 500, -8500--, -8500, 'Despatch'
union all select 2, 468612, 500, -11500--, -20000, 'Despatch'
union all select 3, 468612, 500, -3500--, -23500, 'Despatch'


;with x (id, subid, cardID, DespatchValue, Spend, SumSpend, DespatchBalance, Despatch) as 
(
    --Anchor - beginning record
    select id, 0, cardID, DespatchValue, Spend
    , Spend as SumSpend
    , DespatchValue as DespatchBalance
    , 'Despatch' as Despatch
    from @txn
    where id = 0

    UNION ALL       
    -- primary CTE - identify all nominal 'Topup' records
    select t.id, 0, t.cardID, t.DespatchValue, t.Spend
    , x.SumSpend + t.Spend
    , x.DespatchBalance + t.Spend
    , 'Topup' 
    from @txn t
    join x
        on x.id + 1 = t.id
        and x.subid = 0
    where x.DespatchBalance <= 0

    UNION ALL 

    -- These two UNIONs do a split record:

    -- First half of split - the remaining amount to a balance of 0
    select t.id, 1 -- special "subid" to indicate it's a split record
    , t.cardID, t.DespatchValue
    , - x.DespatchBalance
    , x.SumSpend - x.DespatchValue -- only capture the remaing bit above balance
    , 0 -- DespatchBalance should be 0
    , 'Balanace' 
    from @txn t
    join x
        on x.id + 1 = t.id
        and x.subid = 0
    where x.DespatchBalance > 0
        and x.DespatchBalance + t.Spend < 0

    UNION ALL 
    -- Second half of split - record that this is an overflow after "Balance" reached
    select t.id, 0
    , t.cardID, t.DespatchValue
    , t.Spend + x.DespatchBalance
    , x.SumSpend + t.Spend 
    , x.DespatchBalance + t.Spend
    , 'Topup' 
    from @txn t
    join x
        on x.id + 1 = t.id
        and x.subid = 0
    where x.DespatchBalance > 0
        and x.DespatchBalance + t.Spend < 0
)

select *
from x
option (MAXRECURSION 100)
...