2013-04-22 2 views
4

Я хочу, чтобы выбрать все самые дешевые игрушки моей акции, на сумму в общей сложности 10,0 USD:Как ограничить выбор по сумме?

То есть, я хочу сделать что-то, что выглядит следующим образом:

select * from toy where sum(price) < 10.0 order by price;

Что бы правильный SQL?

Чтобы сделать его более ясным, я приведу пример. Предположим, у меня есть эти пункты в моей таблице:

 name  | price 
------------------+------- 
car    |  1 
boat    |  2 
telephone   |  8 
gold bar   | 50 

В результате я был бы: 1 автомобиль и 1 катер.

Общая стоимость закупки: 3 USD. Я не могу выбрать телефон, потому что он будет составлять 13 долларов США, а это больше 10.

Любые идеи?

+1

Какие СУБД вы используете? –

+0

как сортируются записи? у вас есть ключ автоматического увеличения? –

+0

Они сортируются случайным образом. Я хотел бы сортировать по цене. – mentatkgs

ответ

4

Try:

SELECT a.name, max(a.price) price 
FROM Toy a 
JOIN Toy b 
    on a.price > b.price or (a.price=b.price and a.name>=b.name) 
GROUP BY a.name 
HAVING SUM(b.price) <= 10.0 
order by 2 

SQLFiddle here.

+1

+1 Запрос выполняется в соответствии с требованием OP. Не могли бы вы объяснить данный запрос? – hims056

+2

@ hims056: Конечно - для каждой записи в «Игрушке» (псевдоним) запрос ссылается на все записи в одной таблице (псевдоним b), которые имеют более низкую цену (или такую ​​же цену, но с более низким или равным именем), затем проверяет, добавили ли цены связанных записей не более 10. –

+2

Я бы предположил, что использование функции окна для вычисления текущей суммы (см. ответ Клодоалдо) будет более эффективным. –

2

Вот реализация с использованием рекурсивного CTE. Для этого есть другие решения, вы можете использовать Google для «текущих итогов».

WITH RECURSIVE CTE_RN AS 
(
    SELECT *, ROW_NUMBER() OVER (ORDER BY Price) RN FROM Toys 
) 
, CTE_Rec AS 
(
    SELECT name, price, rn FROM CTE_RN WHERE RN = 1 
    UNION ALL 
    SELECt r.name, a.price + r.price as price, r.rn FROM CTE_RN r 
    INNER JOIN CTE_Rec a on a.RN + 1 = r.RN 
    where a.price+r.price <= 10 
) 
SELECT name, price as total_price FROM CTE_Rec 

SQLFiddle Demo

PS: Это в значительной степени зависит от СУБД, так вот почему это было важно включить эту информацию в начале.

4

SQL Fiddle

select name, price, total 
from (
    select 
     name, price, 
     sum(price) over(
      order by price 
      rows between unbounded preceding and current row 
     ) total 
    from toy 
) s 
where total <= 10 
order by price 

Обратите внимание, что в то время как between unbounded preceding and current row является кадр по умолчанию, режим по умолчанию range. Поэтому необходимо иметь не менее rows unbounded preceding, объявленных как текущая строка, является окончанием по умолчанию для кадра.

+0

Просто примечание стороны: указание «строк между неограниченной предыдущей и текущей строкой» на самом деле не требуется, поскольку это значение по умолчанию. –

+0

@a_horse См. Мой отредактированный ответ. –

Смежные вопросы