简体   繁体   中英

How to get previous and next row's value effeciently in SQL server

Say I have these rows,

InstrumentID

547
698
708

InstrumentID is not autogenerated column.

Say if I pass the parameter in procedure as 698, I should get previous value as 547 and next value as 708. How do I do this efficiently in SQL?

I have this procedure but it is not efficient (and not correct).

Alter PROCEDURE GetNextAndPreviousInsturmentID
(
    @InstrumentID   varchar(14),
    @PreviousInstrumentID   varchar(14) OUT,
    @NextInstrumentID   varchar(14) OUT
)
AS
BEGIN
    Declare @RowNum int = 0

    Select @RowNum = ROW_NUMBER() Over (Order by Cast(@InstrumentID as decimal(18))) From Documents Where InstrumentID = @InstrumentID 

    ;With normal As
    (   
        Select ROW_NUMBER() Over (Order by Cast(@InstrumentID as decimal(18))) as RowNum, Cast(InstrumentID as decimal(18)) as InstrumentID
            From Documents 
    )
    Select @PreviousInstrumentID = InstrumentID From normal
        Where RowNum = @RowNum - 1
    Select @NextInstrumentID = InstrumentID From normal
        Where RowNum = @RowNum + 1

END
GO

Here is a simpler solution, still it's more efficient

SELECT P.PreviousID, N.NextID
FROM
(SELECT  MAX(D.InstrumentID) PreviousID
FROM Documents D
WHERE InstrumentID < @InstrumentID) P
CROSS JOIN
(SELECT  MIN(D.InstrumentID) NextID
FROM Documents D
WHERE InstrumentID > @InstrumentID) N

Try this:

Alter PROCEDURE GetNextAndPreviousInsturmentID
(
    @InstrumentID   varchar(14),
    @PreviousInstrumentID   varchar(14) OUT,
    @NextInstrumentID   varchar(14) OUT
)
AS
BEGIN

    Declare @Ids TABLE(Id varchar(14))

    ;With normal As
    (   
        --Numerate our rows
        Select ROW_NUMBER() Over (Order by Cast(Documents.InstrumentID as decimal(18)) as RowNumber,
               Documents.InstrumentID
        From Documents 

    )
    --Insert three rows from our table with our id and previos/next id
    INSERT INTO @Ids(Id)
    SELECT TOP(3) normal.InstrumentID
    FROM normal
    WHERE RowNumber >=
        (
            SELECT RowNumber - 1
            FROM normal
            WHERE normal.InstrumentID = @InstrumentID
        )
    ORDER BY normal.RowNumber
    --select next and previos ids

    SELECT @PreviousInstrumentID = Min(CAST(Id as decimal(18))),
           @NextInstrumentID = MAX(CAST(Id as decimal(18)))
    FROM @Ids
END
GO

In MS SQL 2012 we have new window functions like FIRST_VALUE and LAST_VALUE, unfortunately in sql 2008 these functions are missing.

WITH CTE AS (
  SELECT rownum = ROW_NUMBER() OVER (ORDER BY p.LogDate), p.LogDate
  FROM DeviceLogs p
)
SELECT prev.logdate PreviousValue, CTE.logdate, nex.logdate NextValue
FROM CTE
LEFT JOIN CTE prev ON prev.rownum = CTE.rownum - 1
LEFT JOIN CTE nex ON nex.rownum = CTE.rownum + 1

GO

Hi I think this will be much more efficient:

Select Next :

select top 1 ID from mytable
where ID >'698'
order by ID asc

Select Prev:

select top 1 ID from mytable
where ID <'698'
order by ID desc

select

LAG(InstrumentID) OVER (ORDER BY InstrumentID) PreviousValue,
InstrumentID, 
LEAD(InstrumentID) OVER (ORDER BY InstrumentID) NextValue
from documents

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM