Как я могу выбрать лучшие 2 или 3 книги, не используя операцию "сверху"
У меня есть таблица с именами книг (book_name, price). Я использую SQL SERVER 2008. Мне нужно получить две лучшие книги, которые имеют максимальные цены.
Я использовал это:
Select * From bb n Where (Select Count(book) From bb
Where book <> n.book
And
price > n.price
) >=2 // or 3 it must be flexible
но дает мне неправильный ответ:( .
не разрешается использовать операции top или order by или функции OLAP, просто запрос.
2 ответа
Вы могли бы использовать функции ранжирования вместо top
with cte as(
select *,row_number() over(order by price desc) as price from table
)
select * from cte where price<=2
Отказ от ответственности: я не призываю никого следовать методам, описанным в этом посте, в любой реальной ситуации. Я занимался этим вопросом только потому, что это теоретический вызов.
Я предполагаю, что это теоретический вопрос / учебник / домашнее задание, я не могу придумать причину не использовать order by
в реальной жизненной ситуации, но здесь идет:
SELECT * FROM bb
WHERE price = (SELECT MAX(price) FROM bb)
OR price = (SELECT MAX(price) FROM bb WHERE price < (SELECT MAX(price) FROM bb))
Обратите внимание, что это даст более 2 строк, если ваш ценовой столбец не уникален. Вы можете это исправить, но тогда это становится довольно сложно:D
;WITH ids AS
(
SELECT id FROM bb
WHERE price = (SELECT MAX(price) FROM bb)
OR price = (SELECT MAX(price) FROM bb
WHERE price < (SELECT MAX(price) FROM bb))
)
SELECT * FROM bb
WHERE id = (SELECT MAX(id) FROM ids)
OR id = (SELECT MAX(id) FROM ids WHERE id < (SELECT MAX(id) FROM ids))
Однако, если вы действительно хотите получить лучшие 2 цены, вы можете сделать это следующим образом:
SELECT MAX(price) as price FROM bb
UNION
SELECT MAX(price) FROM bb WHERE price < (SELECT MAX(price) FROM bb)
edit # 62 Хорошо, я понял это, заняло у меня достаточно много времени. Вы даже заставляли меня дурачиться с рекурсивными cte, пока я не понял, что это действительно так просто, как присвоить звание каждой записи и выбросить мусор. Этот запрос крайне неэффективен, но до настоящего времени он удовлетворял всем вашим требованиям. Также обратите внимание, что результаты не упорядочены. Это именно то, что order by
для:D
DECLARE @NumberOfRecords int
SET @NumberOfRecords = 3
;WITH bb_extended AS
(
SELECT
(
SELECT COUNT(*) + 1 FROM bb AS bb2
WHERE bb2.price > bb.price
OR (bb2.price = bb.price AND bb2.id < bb.id)
) AS rank,
*
FROM
bb
)
SELECT * FROM bb_extended
WHERE rank <= @NumberOfRecords
Вы можете даже сократить это далее (но вы потеряете информацию о ранге):
DECLARE @NumberOfRecords int
SET @NumberOfRecords = 3
SELECT * FROM bb WHERE @NumberOfRecords > (
SELECT COUNT(*) + 1 FROM bb AS bb2
WHERE bb2.price > bb.price
OR (bb2.price = bb.price AND bb2.id < bb.id)
)
Шутки в сторону. Не делайте этого.