Хранимая процедура SQL для суммирования значений и остановки после достижения максимума - PullRequest
1 голос
/ 15 марта 2012

Я хотел бы написать SQL-запрос (SQL Server), который будет возвращать строки (в заданном порядке), но только до заданной суммы.Мой клиент заплатил мне определенную сумму, и я хочу вернуть только те строки, которые <= к этой сумме.</p>

Например, если клиент заплатил мне 370 долларов, а данные в таблице -

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

, я бы хотел вернуть только строки 1, 2 и 3

Это должно быть эффективно, так как будет тысячи строк, поэтому цикл for не будет идеальным, я думаю.Или SQL Server достаточно эффективен для оптимизации хранимого процесса с циклами for?

Заранее спасибо.Джим.

Ответы [ 3 ]

3 голосов
/ 15 марта 2012

Существует несколько вариантов.

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 голосов
/ 15 марта 2012

как то так:

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
0 голосов
/ 15 марта 2012

Прямой подход:

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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...