sql >> Database >  >> RDS >> Sqlserver

Kan deze recursieve oplossing worden geschreven in een T-SQL-query met behulp van CTE of OVER?

Lopend totaal. UPDATE tijdelijke tabel 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;

Recursieve oplossing duurt 9 seconden:

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);

UPDATE-tabel duurt 0 seconden:

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;

Die twee benaderingen zouden je op zijn minst een raamwerk kunnen bieden om je vraag op te bouwen.

Trouwens, in SQL Server, in tegenstelling tot MySQL, maakt de volgorde van variabele toewijzing niet uit. Dit:

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

En het volgende:

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

Ze worden beide op dezelfde manier uitgevoerd, d.w.z. de variabele toewijzingen gebeuren eerst, ongeacht de positie van de variabele toewijzing in de instructie. Beide zoekopdrachten hebben dezelfde uitvoer:

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

Op uw exacte tafel, detecteer gewoon kopen/verkopen, u kunt het vermenigvuldigen met respectievelijk 1 en -1, of u ondertekent alleen de velden, b.v. :

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

Als u toevallig upgradet naar SQL Server 2012, volgt hier de eenvoudige implementatie van running total:

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

Over uw exacte probleem:

select OrderID, Qty, 

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

from Test;

UPDATE

Als je je ongemakkelijk voelt bij eigenzinnige update , kunt u een bewakingsclausule plaatsen om te controleren of de volgorde van de rijen die moeten worden bijgewerkt, overeenkomt met de oorspronkelijke volgorde (met behulp van identiteit (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;

Als UPDATE echt rijen in onvoorspelbare volgorde bijwerkt (of dat toevallig zal doen), zal de @RN_Check niet meer gelijk zijn aan RN (identiteitsvolgorde), de code zal een delig-door-nul-fout veroorzaken dan. Met behulp van de bewakingsclausule zal een onvoorspelbare update-bestelling snel mislukken ; als dit gebeurt, is het tijd om een ​​bug in te dienen petitie aan Microsoft om de eigenzinnige update niet zo eigenzinnig te maken :-)

De beschermingsclausule hedge op de inherent imperatieve operatie (variabele toewijzing) is echt sequentieel.



  1. SQL - Hoe hiërarchieën opslaan en navigeren?

  2. ROWIDTONCHAR() Functie in Oracle

  3. Oracle EXPAND_SQL_TEXT gebruiken

  4. Hier zijn drie redenen waarom u piekactiviteit in uw SQL-instantie zou kunnen zien