sql >> Databáze >  >> RDS >> Sqlserver

Lze toto rekurzivní řešení zapsat do T-SQL Query pomocí CTE nebo OVER?

Průběžný součet. UPDATE dočasná tabulka vs CTE

create table Test(
    OrderID int primary key,
    Qty int not null
);



declare @i int = 1;

while @i <= 5000 begin
    insert into Test(OrderID, Qty) values (@i * 2,rand() * 10); 
    set @i = @i + 1;
end;

Rekurzivní řešení trvá 9 sekund:

with T AS
(
    select ROW_NUMBER() over(order by OrderID) as rn, * from test
)
,R(Rn, OrderId, Qty, RunningTotal) as
(
    select Rn, OrderID, Qty, Qty
    from t 
    where rn = 1

    union all

    select t.Rn, t.OrderId, t.Qty, p.RunningTotal + t.Qty
    from t t
    join r p on t.rn = p.rn + 1

)
select R.OrderId, R.Qty, R.RunningTotal from r
option(maxrecursion 0);

AKTUALIZOVAT tabulku trvá 0 sekund:

create function TestRunningTotal()
returns @ReturnTable table(
    OrderId int, Qty int, RunningTotal int
)
as begin

    insert into @ReturnTable(OrderID, Qty, RunningTotal)
    select OrderID, Qty, 0 from Test
    order by OrderID;

    declare @RunningTotal int = 0;

    update @ReturnTable set 
           RunningTotal = @RunningTotal, 
           @RunningTotal = @RunningTotal + Qty;

    return;
end;

Tyto dva přístupy by vám mohly alespoň poskytnout rámec, na kterém můžete svůj dotaz postavit.

BTW v SQL Server, na rozdíl od MySQL, na pořadí přiřazení proměnných nezáleží. Toto:

update @ReturnTable set 
    RunningTotal = @RunningTotal, 
    @RunningTotal = @RunningTotal + Qty;

A následující:

update @ReturnTable set 
    @RunningTotal = @RunningTotal + Qty,
    RunningTotal = @RunningTotal; 

Oba se provádějí stejným způsobem, tj. k přiřazení proměnných dojde nejdříve, bez ohledu na pozici přiřazení proměnných v příkazu. Oba dotazy mají stejný výstup:

OrderId     Qty         RunningTotal
----------- ----------- ------------
2           4           4
4           8           12
6           4           16
8           5           21
10          3           24
12          8           32
14          2           34
16          9           43
18          1           44
20          2           46
22          0           46
24          2           48
26          6           54

Na vašem přesném stole stačí detekovat nákup/prodej, můžete to buď vynásobit 1 a -1, nebo pole pouze podepíšete, např. :

update @ReturnTable set 
       @RunningTotal = @RunningTotal + 
                       CASE WHEN BuySell = 'Buy' THEN Qty ELSE -Qty END,
       RunningTotal = @RunningTotal;            

Pokud náhodou upgradujete na SQL Server 2012, zde je jednoduchá implementace běhu celkem:

select OrderID, Qty, sum(Qty) over(order by OrderID) as RunningTotal
from Test

K vašemu přesnému problému:

select OrderID, Qty, 

   sum(CASE WHEN BuySell = 'Buy' THEN Qty ELSE -Qty END) 
   over(order by OrderID) as RunningTotal

from Test;

AKTUALIZACE

Pokud se necítíte dobře s zvláštní aktualizace , můžete vložit ochrannou doložku, abyste zkontrolovali, zda pořadí řádků k aktualizaci odpovídá původnímu pořadí (pomocí identity(1,1)):

create function TestRunningTotalGuarded()
returns @ReturnTable table(
    OrderId int, Qty int, 
    RunningTotal int not null, 
    RN int identity(1,1) not null
)
as begin

    insert into @ReturnTable(OrderID, Qty, RunningTotal)
    select OrderID, Qty, 0 from Test
    order by OrderID;

    declare @RunningTotal int = 0;

    declare @RN_check INT = 0;

    update @ReturnTable set 
            @RN_check = @RN_check + 1,
            @RunningTotal = 
                (case when RN = @RN_check then @RunningTotal + Qty else 1/0 end),
            RunningTotal = @RunningTotal;

    return;

end;

Pokud UPDATE skutečně aktualizuje řádky v nepředvídatelném pořadí (nebo náhodou bude), @RN_Check se již nebude rovnat RN (pořadí identity), kód vyvolá chybu dělení nulou pak. Pomocí ochranné doložky rychle selže nepředvídatelné pořadí aktualizací; pokud k tomu dojde, bude čas nahlásit chybu petice společnosti Microsoft, aby ta svérázná aktualizace nebyla tak svérázná :-)

Zajištění ochranné klauzule u inherentně imperativní operace (přiřazení proměnné) je skutečně sekvenční.



  1. Nejlepší fóra o výkonu SQL Serveru pro nápovědu k nejobtížnějším otázkám

  2. Django/MySQL-python - Připojení pomocí starého (před 4.1.1) ověřovacího protokolu odmítnuto (možnost klienta 'secure_auth' povolena)

  3. Jak použít proměnnou v readystatement pro dotaz SQL?

  4. Vzorec Pearsonova korelačního koeficientu v SQL