我有像tblCustData
ID UserID Fee FeePaid
1 12 150 0
2 12 100 0
3 12 50 0
要在FeePaid
列中更新值,以便@Amt
中的200
变量中有值,那么它应该更新任何两行
输出应该像
ID UserID Fee FeePaid
1 12 150 150
2 12 100 50
3 12 50 0
FeePaid
不应该比Fee
列更重要但如果我在350
变量中传递@Amt
,它应该产生类似
ID UserID Fee FeePaid
1 12 150 200
2 12 100 100
3 12 50 50
仅当@Amt
超过Fee
列中的总值
我想不出这个问题
Update tblCustData
Set FeePaid=@Amt
Where UserID=12
答案 0 :(得分:5)
首先使用CTE语法,我们准备一个带有sums分布的表,然后使用唯一字段Code
使用CASE更新主表来处理所有可能的方式(包括带有余数的第一行)。
Declare @Amt int;
SET @Amt=250;
with T as
(
SELECT ROW_NUMBER() OVER (ORDER BY Fee desc) as rn, *
FROM tblCustData WHERE UserId=12
)
,T2 as
(
SELECT *,
ISNULL((SELECT SUM(Fee-FeePaid) FROM T WHERE T1.RN<RN),0) as PrevSum
FROM T as T1
)
UPDATE
A
SET A.FeePaid = A.FeePaid+ CASE WHEN (B.PrevSum+B.Fee-B.FeePaid<=@Amt)
AND (B.RN<>1)
THEN B.Fee-B.FeePaid
WHEN (B.PrevSum+B.Fee-B.FeePaid<=@Amt) AND (B.RN=1)
THEN @Amt-B.PrevSum
WHEN B.PrevSum>=@Amt
THEN 0
WHEN B.PrevSum+B.Fee-B.FeePaid>@Amt
THEN @Amt-B.PrevSum
END
FROM
tblCustData A
JOIN T2 B ON A.Code = B.Code
GO
答案 1 :(得分:1)
试试..
declare @t table (id int identity, UserId int, Fee money, FeePaid money)
insert into @t (UserID, Fee, FeePaid)
values
(12, 150, 0)
,(12, 100, 0)
,(12, 50 , 0)
declare @amt money = 200; -- change to 400 to test over paid
declare @Fees money;
select @Fees = sum(Fee) from @t;
declare @derivedt table (deid int, id int, UserId int, Fee money, FeePaid money)
insert into @derivedt (deid, id, UserId, Fee, FeePaid)
select row_number() over (order by case when @amt <= @Fees then id else -id end asc), id, UserId, Fee, FeePaid
from @t
-- order by case when @amt <= @Fees then id else -id end asc
; with cte(deid, id, UserId, Fee, FeePaid, Remainder)
as
(
select 0 as deid, 0 as id, 0 as UserId, cast(0.00 as money) as Fee, cast(0.00 as money) as FeePaid , @Amt as Remainder
from @derivedt
where id = 1
union all
select t.deid, t.id, t.UserId, t.Fee, case when cte.Remainder > t.Fee then t.Fee else cte.Remainder end as FeePaid
, case when cte.Remainder > t.Fee then cte.Remainder - t.Fee else 0 end as Remainder
from @derivedt t inner join cte cte on t.deid = (cte.deid + 1)
)
update origt
set FeePaid = det.FeePaid
from @t origt
inner join
(
select cte1.deid, cte1.id, cte1.UserId, cte1.Fee, cte1.FeePaid + ISNULL(cte2.Remainder, 0) as FeePaid
from cte cte1
left outer join (select top 1 deid, Remainder from cte order by deid desc) cte2
on cte1.deid = cte2.deid
where cte1.deid > 0
) det
on origt.id = det.id
select *
from @t
修改为持续更新值..
-- Create table once and insert into table once
create table #t (id int identity, UserId int, Fee money, FeePaid money)
insert into #t (UserID, Fee, FeePaid)
values
(12, 150, 0)
,(12, 100, 0)
,(12, 50 , 0)
-- ===============================
-- Run multiple times to populate #t table
declare @amt money = 100; -- change to 400 to test over paid
declare @Fees money;
select @Fees = sum(Fee - FeePaid) from #t;
declare @derivedt table (deid int, id int, UserId int, Fee money, FeePaid money)
insert into @derivedt (deid, id, UserId, Fee, FeePaid)
select row_number() over (order by case when @amt <= @Fees then id else -id end asc), id, UserId, (Fee - FeePaid) as Fee, FeePaid
from #t
-- order by case when @amt <= @Fees then id else -id end asc
; with cte(deid, id, UserId, Fee, FeePaid, Remainder)
as
(
select 0 as deid, 0 as id, 0 as UserId, cast(0.00 as money) as Fee, cast(0.00 as money) as FeePaid , @Amt as Remainder
from @derivedt
where id = 1
union all
select t.deid, t.id, t.UserId, t.Fee, case when cte.Remainder >= t.Fee then t.Fee else cte.Remainder end as FeePaid
, case when cte.Remainder >= t.Fee then cte.Remainder - t.Fee else 0 end as Remainder
from @derivedt t inner join cte cte on t.deid = (cte.deid + 1)
)
update origt
set FeePaid = origt.FeePaid + det.FeePaid
from #t origt
inner join
(
select cte1.deid, cte1.id, cte1.UserId, cte1.Fee, cte1.FeePaid + ISNULL(cte2.Remainder, 0) as FeePaid, cte1.Remainder
from cte cte1
left outer join (select top 1 deid, Remainder from cte order by deid desc) cte2
on cte1.deid = cte2.deid
where cte1.deid > 0
) det
on origt.id = det.id
select *
from #t
-- Drop temp table after
-- drop table #t
答案 2 :(得分:-2)
除了您的代码,我在您的表中添加了一个标识列。见代码。
DECLARE @TAB TABLE(ID INT IDENTITY(1,1),USERID INT, FEE INT, FEEPAID INT)
INSERT INTO @TAB VALUES (12,150,0),(12,100,0),(12,50,0)
DECLARE @AMOUNT INT = 230,
@AMOUNTNEW INT = 0,
@B INT = 1,
@S INT = 1,@E INT = (SELECT COUNT(*) FROM @TAB)
WHILE @S <= @E
BEGIN
UPDATE LU
SET LU.FEEPAID = CASE WHEN @AMOUNT >= FEE THEN FEE ELSE @AMOUNT END
FROM @TAB LU
WHERE LU.ID = @S
SET @AMOUNT = @AMOUNT - (SELECT FEE FROM @TAB WHERE ID = @S)
IF @AMOUNT <= 0
SET @S = @E
SET @S = @S + 1
END
SELECT * FROM @TAB
<强>结果:强>
我希望这个想法很明确,我们可以从这里开始工作。