Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Giải pháp đệ quy này có thể được viết thành Truy vấn T-SQL bằng CTE hoặc OVER không?

Tổng số đang chạy. CẬP NHẬT bảng tạm thời so với 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;

Giải pháp đệ quy mất 9 giây:

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

Bảng CẬP NHẬT mất 0 giây:

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;

Hai cách tiếp cận đó ít nhất có thể cung cấp cho bạn một khuôn khổ để xây dựng truy vấn của bạn.

BTW trong SQL Server, không giống như trong MySQL, thứ tự gán biến không quan trọng. Cái này:

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

Và những điều sau:

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

Cả hai đều thực thi theo cùng một cách, tức là các phép gán biến xảy ra đầu tiên, bất kể vị trí của phép gán biến trong câu lệnh. Cả hai truy vấn đều có cùng đầu ra:

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

Trên bảng chính xác của bạn, chỉ cần phát hiện Mua / Bán, bạn có thể nhân nó với 1 và -1 tương ứng hoặc bạn chỉ cần ký tên vào các trường, ví dụ::

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

Nếu bạn tình cờ nâng cấp lên SQL Server 2012, đây là cách triển khai đơn giản của tổng số đang chạy:

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

Về vấn đề chính xác của bạn:

select OrderID, Qty, 

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

from Test;

CẬP NHẬT

Nếu bạn cảm thấy không ổn với cập nhật kỳ quặc , bạn có thể đặt một điều khoản bảo vệ để kiểm tra xem thứ tự của các hàng sẽ được cập nhật có khớp với thứ tự ban đầu hay không (được hỗ trợ bởi danh tính (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;

Nếu UPDATE thực sự cập nhật các hàng theo thứ tự không thể đoán trước (hoặc bất kỳ trường hợp nào xảy ra), @RN_Check sẽ không bằng RN (thứ tự nhận dạng) nữa, mã sẽ gây ra lỗi chia cho không sau đó. Sử dụng điều khoản bảo vệ, thứ tự cập nhật không thể đoán trước sẽ không nhanh ; nếu điều này xảy ra sau đó, đây sẽ là lúc để gửi một bug kiến nghị với Microsoft để làm cho bản cập nhật kỳ quặc không kỳ quặc như vậy :-)

Mệnh đề bảo vệ hàng rào đối với hoạt động mệnh lệnh vốn có (gán biến) thực sự là tuần tự.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Lỗi tràn số học (số thành số) với MERGE:Lỗi SQL Server?

  2. phân tách các giá trị được phân tách bằng dấu phẩy và lưu trữ trong bảng trong máy chủ sql

  3. Sao chép bảng vào cơ sở dữ liệu khác trên SQL Server khác

  4. Làm cách nào để lấy kết xuất SQL của cơ sở dữ liệu SQL Server 2008?

  5. UCS-2 và SQL Server