在存储过程中(我使用的是SQL server2008),我有这样的业务:
ID City Price Sold
1 A 10 3
1 B 10 5
1 A 10 1
1 B 10 3
1 C 10 5
1 C 10 2
2 A 10 1
2 B 10 6
2 A 10 3
2 B 10 4
2 C 10 3
2 C 10 4
我想做的是:
每个ID,按城市排序。
排序后,对于此ID的每一行,从上到下重新计算出售条件:每个ID的销售总额不超过价格(如下结果)。
结果如下:
ID City Price Sold_Calculated
1 A 10 3
1 A 10 1
1 B 10 5
1 B 10 1 (the last one equal '1': Total of Sold = Price)
1 C 10 0 (begin from this row, Sold = 0)
1 C 10 0
2 A 10 1
2 A 10 3
2 B 10 6
2 B 10 0 (begin from this row, Sold = 0)
2 C 10 0
2 C 10 0
现在,我正在使用Cursor执行此任务:获取每个ID,排序City,然后计算Sold,并保存到临时表。完成计算后,联合所有临时表。但这需要很长时间。
我知道人们建议的是,不要使用光标。
所以,通过这个任务,你能给我一个例子(使用选择形式,哪个组)完成?还是我们有其他方法可以快速解决?
我理解这项任务对你来说并不容易,但我仍然在这里发帖,希望有人帮助我完成。
我很感激你的帮助。
感谢。
答案 0 :(得分:3)
为了完成你的任务,你需要计算一个运行总和并使用一个案例陈述
Previously我使用JOIN来执行运行总和和滞后的案例陈述
然而,使用递归Cte计算as described here的运行总计Aaron Bertand和case statement Andriy M我们可以构建以下内容,这应该提供最佳性能并且不需要“偷看前一行”
WITH cte
AS (SELECT Row_number()
OVER ( partition BY id ORDER BY id, city, sold DESC) RN,
id,
city,
price,
sold
FROM table1),
rcte
AS (
--Anchor
SELECT rn,
id,
city,
price,
sold,
runningTotal = sold
FROM cte
WHERE rn = 1
--Recursion
UNION ALL
SELECT cte.rn,
cte.id,
cte.city,
cte.price,
cte.sold,
rcte.runningtotal + cte.sold
FROM cte
INNER JOIN rcte
ON cte.id = rcte.id
AND cte.rn = rcte.rn + 1)
SELECT id,
city,
price,
sold,
runningtotal,
rn,
CASE
WHEN runningtotal <= price THEN sold
WHEN runningtotal > price
AND runningtotal < price + sold THEN price + sold - runningtotal
ELSE 0
END Sold_Calculated
FROM rcte
ORDER BY id,
rn;
答案 1 :(得分:1)
正如@Gordon Linoff评论的那样,问题的排序顺序并不清楚。出于本答案的目的,我假设排序顺序为city, sold.
select id, city, price, sold, running_sum,
lag_running_sum,
case when running_sum <= price then Sold
when running_sum > price and price > coalesce(lag_running_sum,0) then price - coalesce(lag_running_sum,0)
else 0
end calculated_sold
from
(
select id, city, price, sold,
sum(sold) over (partition by id order by city, sold
rows between unbounded preceding and current row) running_sum,
sum(sold) over (partition by id order by city, sold
rows between unbounded preceding and 1 preceding) lag_running_sum
from n_test
) n_test_running
order by id, city, sold;
以下是Oracle的demo。
让我打破查询。
我使用SUM作为分析函数来计算运行总和。
id
对行进行分组,并在每个组中按city and sold
对行进行排序。
rows between
子句指出要考虑添加哪些行。在这里我已指定添加
当前行和它上面的所有其他行。这给出了运行总和。将此结果用作内联视图,外部选择使用CASE
语句来确定
新栏的价值。
希望我的解释非常清楚。
答案 2 :(得分:0)
对我来说,听起来你可以在这种情况下使用window functions。这适用吗?
虽然在我的情况下你的最终结果可能如下:
ID City Price Sold_Calculated
2 A 10 4
2 B 10 6
2 C 10 0
可能有像
这样的聚合SUM(Sold_Calculated) OVER (PARTITION BY ID, City, Price, Sold_Calculated)
取决于您想要走多远..如果需要,您甚至可以使用案例陈述
答案 3 :(得分:0)
您是否希望在SQL中完全执行此操作?一个简单的方法是:
SELECT C.ID,
C.City,
C.Price,
calculate_Sold_Function(C.ID, C.Price) AS C.Sold_Calculated
FROM CITY_TABLE C
GROUP BY C.City
其中 calculate_Sold_Function 是以ID和Price为参数的T-SQL / MySQL / etc函数。不知道你打算如何计算价格。