2015-05-17 14 views
5

Tôi có một kịch bản live-trường hợp đơn giản trên SQL Server 2014. Tôi có một bảng với đơn đặt hàng và quanities của họ:T-SQL phân phối giá trị giữa các hàng mà không cần một con trỏ

declare @qty_to_distribute int = 50 

create table orders (id int, priority int, qty int) 

insert into orders (id, priority, qty) values 
(1, 1, 10), 
(2, 2, 30), 
(3, 3, 20), 
(4, 4, 5) 

Tôi có một giá trị, ví dụ 50, mà tôi phải phân phối giữa các đơn đặt hàng, dựa trên ưu tiên của họ Iiterating thông qua lệnh

  • nếu số tiền còn lại là lớn hơn sau đó quanity của trật tự hiện hành, thứ tự sẽ được thực hiện, và @qty_to_distribute giảm theo số lượng đơn đặt hàng,
  • nếu không - đơn đặt hàng bị hủy.

Nhìn vào dữ liệu mẫu - các đơn hàng 1, 2 và 4 sẽ được nhận ra và # 3 bị hủy.

Có một giải pháp đơn giản, hiệu quả và không phải con trỏ, tốt nhất là dựa trên chức năng cửa sổ?

này sẽ hứa hẹn, nhưng không thể tìm ra nơi để đặt các điều kiện:

select id, 
sum(qty) OVER (ORDER BY priority asc ROWS UNBOUNDED PRECEDING) as qtysum 
from orders 

id qtysum 
1 10 
2 40 
3 60  * 
4 65  * 

http://sqlfiddle.com/#!6/05fa2/2/0

+0

Nhờ sự giúp đỡ, làm việc cho tôi perfecty, và xin lỗi, được AFK cho một còn thời gian. – malpka

+0

cảm ơn, tôi đã xóa bình luận trước đó của tôi :-) –

Trả lời

6

Hãy thử điều này:

create table o (id int, priority int, qty int) 

insert into o (id, priority, qty) values 
(1, 1, 10), 
(2, 2, 30), 
(3, 3, 20), 
(4, 4, 5), 
(5, 5, 1), 
(6, 6, 10) 

with cte1 as(select *, row_number() over(order by priority) as rn from o), 
cte2 as(
    select top 1 id, priority, qty, rn, 
    case when qty > 50 then 1 else 0 end as ToBeCanceled 
    from cte1 order by rn 
    Union all 
    select cte1.id, cte1.priority, case when cte2.qty + cte1.qty > 50 then cte2.qty 
    else cte2.qty + cte1.qty end as qty, 
    cte1.rn, 
    case when cte2.qty + cte1.qty > 50 then 1 else 0 end as ToBeCanceled 
    from cte1 
    join cte2 on cte1.rn = cte2.rn + 1) 
select id, priority, ToBeCanceled from cte2 
option(maxrecursion 0) 

Output:

id ToBeCanceled 
1 0 
2 0 
3 1 
4 0 
5 0 
6 1 

Fiddle http://sqlfiddle.com/#!6/87ac9/19

4

CẬP NHẬT nhờ Giorgi Nakeuri

WITH Intermediate AS (
    SELECT 
     Id, 
     ROW_NUMBER() OVER (ORDER BY Priority) as Priority, 
     qty     
    FROM Orders), 
Result AS 
(
    SELECT 
     Id, 
     Priority, 
     CASE when qty < 50 THEN 0 ELSE qty END as Residual, 
     CASE when qty < 50 THEN 50 - qty ELSE 50 END as Remaining 
    FROM Intermediate 
    WHERE Priority = 1 
    UNION ALL 
    SELECT 
     ORD.Id, 
     ORD.Priority, 
     CASE when ORD.qty < Result.Remaining THEN 0 ELSE qty END as Residual, 
     CASE when ORD.qty < Result.Remaining THEN Result.Remaining - ORD.qty ELSE Result.Remaining END as Remaining 
    FROM Intermediate ORD INNER JOIN Result ON ORD.Priority = Result.Priority + 1 
) 
    select Id, Priority, Residual, Remaining from result 

http://sqlfiddle.com/#!6/2ac98f/2

+0

Chúng tôi cũng nghĩ như vậy. Bạn có thể sử dụng một cte trong một cái khác. + từ tôi. –

+0

và + từ tôi tại cùng thời điểm chính xác :-) –

+0

Tôi đã cập nhật câu trả lời, nhưng rõ ràng ý tưởng của bạn là :-) –

Các vấn đề liên quan