查询以查找当前包含order by子句的前一行和下一行

时间:2015-05-31 06:58:11

标签: sql-server sql-server-2008

我执行以下查询:

SELECT quotesid 
FROM quotestable 
WHERE quotesauthor LIKE '%Mahatma%'  
ORDER BY popularity DESC

这给了我以下结果:(quotesid - 是主键)

 968
 158
 159
 160
 161

我的要求:

我需要下一个和之前的quotesidORDER BY popularity DESC)。例如,如果我在第158个记录。下一个和前一个值应分别为159和968,我需要在一个查询中使用它。

我的查询

SELECT *  
FROM quotestable 
WHERE 
    (quotesid = (SELECT MIN(quotesid) FROM quotestable where quotesid > 158 and quotesauthor like '%Mah%' ) 
 OR quotesid = (SELECT MAX(quotesid) FROM quotestable where quotesid < 158 and quotesauthor like '%Mah%' ))
ORDER BY popularity DESC

这不起作用。这给了我一条记录 - 159。 有没有办法编写单个查询并根据需要获得结果?

小提琴:

sql-fiddle

3 个答案:

答案 0 :(得分:1)

也许,这对你有用。它会为您的查询提供row number索引,然后left outer join本身会移动+1-1记录,以生成[next][previous]列。

with cte as
(
    select quotesid, ROW_NUMBER() over (order by popularity desc) as [RowNo]
    from quotestable
)
select cte.quotesid, [next].quotesid as [Next], [prev].quotesid as [Previous]
from cte left outer join cte as [next] on cte.RowNo = ([next].RowNo - 1)
         left outer join cte as [prev] on cte.RowNo = ([prev].RowNo + 1)

结果:

quotesid Next   Previous
------------------------
968      158    NULL
158      159    968
159      160    158
160      161    159
161      NULL   160

sql小提琴: http://sqlfiddle.com/#!6/0ac0b/4

答案 1 :(得分:0)

我认为这会给你你想要的东西:

;WITH t AS (
    SELECT *, ROW_NUMBER() OVER (ORDER BY popularity DESC) rn
    FROM quotestable
    WHERE quotesauthor LIKE '%Mah%')
SELECT *
FROM t
WHERE 1 = ABS(t.rn - (SELECT rn FROM t WHERE quotesid = 158))

您可以使用它将上一行和下一行放在一行:

;WITH t AS (
    SELECT *, ROW_NUMBER() OVER (ORDER BY popularity DESC) rn
    FROM quotestable
    WHERE quotesauthor LIKE '%Mah%')
SELECT t1.quotesid, t2.quotesid PrevID, t3.quotesid NextID
FROM t t1 
    LEFT JOIN t t2 ON t1.rn = t2.rn - 1
    LEFT JOIN t t3 ON t1.rn = t3.rn + 1
WHERE t1.rn = (SELECT rn FROM t WHERE quotesid = 158)

答案 2 :(得分:0)

select quotestable.quotesid, b.quotesid nextQuoteID, c.quotesid previousQuoteID from quotestable
join (
    select a.quotesID, max(b.popularity) previousQuoteID, min(c.popularity) nextQuoteID
    from quotestable a
    left join quotestable b
    on a.popularity > b.popularity
    left join quotestable c
    on a.popularity < c.popularity
    where a.author like '%Mahatma%'
    group by a.quotesid
) x
on quotestable.quotesid = x.quotesid
left join quotestable b
on b.popularity = x.previousquoteid
left join quotestable c
on c.popularity = x.nextquoteid
order by quotestable.popularity desc