SQL - Previous/Next Records

I have a table with a GUID ID column and Firstname, Surname fields. I want to be able to select a record using the GUID and also select the previous/next record sorted by the Firstname and Surname fields. So for example, i

Capture2.PNG
In the example above, I want to select record c5875.... (Kevin) and have the previous/next sorted by the 2nd/3rd column and have it display John (prev) and Tracy (next).

Hope that makes sense.
LVL 3
John SmithAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Olaf DoschkeSoftware DeveloperCommented:
See LEAD() and LAG(), if you have SQL2008+

Bye, Olaf.
Pawan KumarDatabase ExpertCommented:
@Olaf Doschke - LEAD() and LAG() were available from SQL Server 2012.
https://msdn.microsoft.com/en-IN/library/hh213125.aspx


SQL Server 2012 introduces new analytical function LEAD() and LAG(). These functions accesses data from a subsequent row (for lead) and previous row (for lag) in the same result set without the use of a self-join .

NEXT Value Sample example - https://msbiskills.com/2012/07/19/t-sql-2/

Previous Value Sample example - https://msbiskills.com/2012/07/19/t-sql-1/

Enjoy !
SharathData EngineerCommented:
To complete Olaf's suggestion.
select *,
       lag(FirstName) over (order by FirstName) Prev,
	   lead(FirstName) over (order by FirstName) Nxt
  from your_table

Open in new window

IT Pros Agree: AI and Machine Learning Key

We’d all like to think our company’s data is well protected, but when you ask IT professionals they admit the data probably is not as safe as it could be.

Olaf DoschkeSoftware DeveloperCommented:
Sorry, yes, wrong promise. It's 2012+ only.

Bye, Olaf.
John SmithAuthor Commented:
Thanks for the responses. That is giving me null values for some reason.
Vitor MontalvãoMSSQL Senior EngineerCommented:
I think the requirement need clarifications:
  • What's happening if you have two Johns or Tracys?
  • And if you want to select Anne (first record) or Tracy (last record)?
John SmithAuthor Commented:
Thanks for the response Vitor. I'm selecting the record by GUID, but want to include the previous / next records based on the Firstname, Surname values.
Olaf DoschkeSoftware DeveloperCommented:
Well, LEAD and LAG only give one sclara value (expression), usually one column of the previous or next row, not the full previous/next row. So you get the next and previous lastname in two extra columns, not as separate rows.

You could query the guids you need to query:
select GUID,
       lag(guid) over (order by FirstName, SurName) PrevGUID,
	   lead(guid) over (order by FirstName, SurName) NxtGUID
  from your_table WHERE GUID = '...'

Open in new window


Bye, Olaf.
Vitor MontalvãoMSSQL Senior EngineerCommented:
I understand you're selecting by GUID but you're getting the previous and next records based in the firstname order and not in the GUID.
Like, Tracy's GUID is not the next one after Kevin's (it should by Geoff's by your example).
SharathData EngineerCommented:
>> That is giving me null values for some reason.
post some sample data where you are getting NULLs.
Olaf DoschkeSoftware DeveloperCommented:
You get NULLS because the main query only fetches one row, you can only get next and previous rows, if the result has more than the one row, that's the problem here.

This is going round in circles, if you first don't know the next and previous neighbors you have to row_number all and then you might also fetch all anyway, and scroll to the one guid.

Bye, Olaf.
Olaf DoschkeSoftware DeveloperCommented:
A straight forward approach would be along the lines of this

with cte as(
Select * from sys.objects so where so.object_id=5)

Select Top 1 so.* From sys.objects so cross apply cte where so.object_id<cte.object_id
union
Select * From cte
union
Select Top 1 so.* From sys.objects so cross apply cte where so.object_id>cte.object_id
order by object_id

Open in new window


Bye, Olaf.

Edit: Actually would need something alike:

Select * From (Select Top 1 * From sys.objects where object_id<5 order by object_id desc) t1
union all
(Select                     * From sys.objects where object_id=5)
union all
Select * From (Select Top 1 * From sys.objects where object_id>5 order by object_id asc) t2

Open in new window

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
John SmithAuthor Commented:
I'll try that and revert.
Vitor MontalvãoMSSQL Senior EngineerCommented:
John, any update of this question?
Pawan KumarDatabase ExpertCommented:
Hey John, Just wanted to check, have you checked code/post i mentioned.?
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft SQL Server

From novice to tech pro — start learning today.