Reputation: 2184
I have a car hire table which records all the dates a car is on hire Onhire
and when it's returned Offhire
. I've been asked to provide the next or follow on hire company name in the results table but I'm not sure how to do it. The hire table is structured as follows:
---------------
| Hire |
---------------
| Id |
| CarId |
| Onhire |
| Offhire |
| HireCompany |
|-------------|
If I run a basic select against that table I see the following data. I've added a WHERE
to pull back a specific car that is still on hire and has a follow on hire shortly after (I am using UK date formatting).
Id | CarId | Onhire | Offhire | HireCompany
-------------------------------------------------------
10 | 272 | 2019-01-01 | 2019-03-01 | Company A
11 | 272 | 2019-03-02 | 2019-04-01 | Company B
-------------------------------------------------------
As you can see, the car is currently on hire until 01/03/2019 but after that, it is going on hire to Company B
on the 02/03/2019. I need my query to show that the car is on hire at the moment but in a column called ForwardHire
(or whatever) show the NEXT company that has it on hire as well as a column that shows the next hire start date.
So, my query would produce the following desired result:
Id | CarId | Onhire | Offhire | ForwardHire | ForwardHireDate
---------------------------------------------------------------------------
10 | 272 | 2019-01-01 | 2019-03-01 | Company B | 2019-03-02
Note: I am already aware of how to return a single result from my Hire table using an outer apply, advice which I got in a different thread.
I hope my question has made sense and that someone can help. In terms of SQL queries, this is a first for me so any advice and guidance are appreciated.
Upvotes: 2
Views: 167
Reputation: 164089
Self join the hire table to the row that has the next onhire
date:
select
h1.*,
h2.hirecompany ForwardHire
h2.onhire ForwardHireDate
from hire h1 left join hire h2
on
(h2.carid = h1.carid)
and
(h2.onhire = (select min(onhire) from hire where carid = h1.carid and onhire > h1.offhire) )
where
h1.carid = 272
and
curdate() between h1.onhire and h1.offhire
Upvotes: 1
Reputation: 14189
Using OUTER APPLY:
SELECT
H.*,
T.ForwardHire,
T.ForwardHireDate
FROM
Hire AS H
OUTER APPLY (
SELECT TOP 1 -- Just the next record
ForwardHire = F.HireCompany,
ForwardHireDate = F.OnHire
FROM
Hire AS F
WHERE
H.CarId = F.CarId AND -- With the same car
F.OnHire > H.OffHire -- With later OnHire
ORDER BY
F.OnHire ASC -- Sorted by OnHire (closeste one first)
) AS T
Upvotes: 3
Reputation: 50163
Are you looking for lead function ? :
SELECT h.*
FROM (SELECT h.*,
LEAD(HireCompany) OVER (PARTITION BY CarID ORDER BY Id) AS ForwardHire,
LEAD(Onhire) OVER (PARTITION BY CarID ORDER BY Id) AS ForwardHireDate
FROM Hire h
) h
WHERE ForwardHire IS NOT NULL AND ForwardHireDate IS NOT NULL;
Upvotes: 3
Reputation: 1269683
Do you just want lead()
?
select h.*,
lead(h.hirecompany) over (partition by h.carid order by h.onhire) as next_hirecompany
from hire h;
Note: this will return the next company, even if there are gaps. If you want the "adjacent" next company, then I'd recommend a left join
:
select h.*, hnext.hirecompany as next_hirecompany
from hire h left join
hire hnext
on hnext.carid = h.carid and
hnext.onhire = dateadd(day, 1, h.offhire);
Upvotes: 2