如何在不使用“顶部”操作的情况下选择前2或3本书的价格

时间:2013-12-07 14:13:37

标签: sql sql-server db2

我有一个名为books的表(book_name,price)我正在使用SQL SERVER 2008 我需要获得他们有最高价格的前2本书

我用过这个:

 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 个答案:

答案 0 :(得分:1)

免责声明:我不鼓励任何人在任何现实生活中遵循本文所述的技巧。我只是因为它的理论挑战而追问这个问题。

我认为这是一个理论/教科书/家庭作业问题,我无法想到在现实生活中使用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))

但是,如果你真的只想要前两个价格,你可以这样做:

SELECT MAX(price) as price FROM bb
UNION
SELECT MAX(price) FROM bb WHERE price < (SELECT MAX(price) FROM bb)

编辑#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)
    )

<强>严重。不要这样做。

答案 1 :(得分:-1)

您可以使用排名功能代替top

 with cte as(

    select *,row_number() over(order by price desc) as price from table
    )

    select * from cte where price<=2