2012-03-14 30 views
1

我想編寫一個SQL查詢(SQL Server),它將返回行(按給定順序)但只能達到給定的總數。我的客戶向我付了一定金額,我只想返回那些數量爲< =的行。SQL存儲過程將值加起來並在達到最大值後停止

例如,如果客戶支付我$ 370,以及數據表是

id amount 
1 100 
2 122 
3 134 
4 23 
5 200 

那麼我想只返回行1,2和3

這必須是有效的,因爲會有成千上萬的行,所以我想,for循環並不理想。或者,SQL Server是否足夠有效地利用for循環優化存儲過程?

在此先感謝。吉姆。

+0

我有一個懷疑,這是爲數不多的場景,其中一個行由行,光標的方法會比一套基於方法快一個... – 2012-03-14 21:47:35

+0

什麼版本你是否在SQL Server上?如果不是2012年,你是否有能力轉向它,因爲它即將被釋放? – 2012-03-14 21:50:28

+0

是用於訂購的ID嗎?您可能可以使用LAG功能。 – Randy 2012-03-14 21:50:31

回答

3

有幾個選項。

1)三角加入

SELECT * 
FROM YourTable Y1 
WHERE (SELECT SUM(amount) 
     FROM YourTable Y2 
     WHERE Y1.id >= Y2.id) <= 370 

2)遞歸CTE

WITH RecursiveCTE 
AS  (
     SELECT TOP 1 id, amount, CAST(amount AS BIGINT) AS Total 
     FROM YourTable 
     ORDER BY id 
     UNION ALL 
     SELECT R.id, R.amount, R.Total 
     FROM (
       SELECT T.*, 
         T.amount + Total AS Total, 
         rn = ROW_NUMBER() OVER (ORDER BY T.id) 
       FROM YourTable T 
       JOIN RecursiveCTE R 
         ON R.id < T.id 
       ) R 
     WHERE R.rn = 1 AND Total <= 370 
     ) 
SELECT id, amount, Total 
FROM RecursiveCTE 
OPTION (MAXRECURSION 0); 

的第二一個將可能有更好的表現。

在SQL Server 2012中,你將能夠所以像

;WITH CTE AS 
(
SELECT id, 
     amount, 
     SUM(amount) OVER(ORDER BY id 
         ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) 
      AS RunningTotal 
    FROM YourTable 
) 
    SELECT * 
    FROM CTE 
    WHERE RunningTotal <=370 

雖然有可能會成爲一個更有效的方式(儘快達到總停止掃描)

+0

選項1運行良好,並且在此階段執行得非常好。感謝堆。 – 2012-03-14 22:59:30

+0

這是我的事件SQL。請注意,子選擇子句中的附加'where'元素提高了性能,而「前100名」確保它不會運行時間過長。 SELECT TOP 100 PerfSearchID,用戶ID,totalPrice FROM PerformedSearches AS P1 WHERE(用戶ID = 210)和(totalPrice <> 0)AND ((SELECT SUM(totalPrice)AS表達式1 FROM PerformedSearches AS P2 WHERE(用戶ID = 210)AND(totalPrice <> 0)AND(P1.PerfSearchID> = PerfSearchID))<= 370) – 2012-03-14 23:04:24

+0

這是我第一次使用stackoverflow.com,它是非常棒的! – 2012-03-14 23:05:02

0

直-forward approach:

SELECT a.id, a.amount 
FROM table1 a 
INNER JOIN table1 b ON (b.id <=a.id) 
GROUP BY a.id, a.amount 
HAVING SUM(b.amount) <= 370 

不幸的是,它有N^2性能問題。

0

是這樣的:

select id from 
(
select t1.id, t1.amount, sum(t2.amount) s 
from tst t1, tst t2 
where t2.id <= t1.id 
group by t1.id, t1.amount 
) 
where s < 370