Reputation: 183
Had a brief search online to see if an answer to this already existed. Couldn't find anything that tackled this particular situation (which was a surprise, as I would have assumed it was fairly common).
Basically I have a table that records registrations with a service, along with the ID of the client registering, and the start and end dates of the registration. See below for an example of the table structure:
Reg ID | Client ID | Reg Start | Reg End
R6 C1 01-06-2016 Null
R5 C2 20-05-2016 02-06-2016
R4 C2 14-03-2016 11-05-2016
R3 C1 10-03-2016 05-05-2016
R2 C2 28-01-2016 02-02-2016
R1 C2 10-11-2015 23-12-2015
What I want to do, is pull the records from the table but also add a column that returns a count of how many previous registrations are in the table with the same client ID for each record. For the sake of clarity, I only want to count registrations for each record that have the same client ID and have a start date less than that of the record.
As such, a successful query would return the following output:
Reg ID | Client ID | Reg Start | Reg End | # previous reg
R6 C1 01-06-2016 Null 1
R5 C2 20-05-2016 02-06-2016 3
R4 C2 14-03-2016 11-05-2016 2
R3 C1 10-03-2016 05-05-2016 0
R2 C2 28-01-2016 02-02-2016 1
R1 C2 10-11-2015 23-12-2015 0
Has anyone had previous experience of doing this who could offer a viable solution?
My initial thought process was to create a sub query that would count registrations grouped by client ID, and then join this to my main query using client ID. For example:
SELECT
t1.reg_id
t1.client_id
t1.reg_start
t1.reg_end
FROM registrations t1
JOIN
(SELECT
client_id
count(reg_id)
FROM registrations
GROUP BY client_id) t2
ON t1.client_id = t2.client_id
However, this would return a count of the total registrations for a given client per record, where as I specifically require the previous registrations.
Any input that the hive mind could provide would be much appreciated. I think I've hit a bit of a wall with my currently quite limited SQL knowledge here :/
Also I should probably mention that I'm using an Oracle database!
Upvotes: 2
Views: 1437
Reputation: 1579
The easiest way, in my opinion, is to build a subquery in the SELECT
statement of main query, as follow:
SELECT
t1.*,
(
SELECT COUNT(*)
FROM registrations t2
WHERE t2.client_id = t1.client_id
AND t2.reg_start < t1.reg_start
) AS previous_reg
FROM registrations t1
ORDER BY reg_id DESC
Upvotes: 0
Reputation:
This can be done with a window function and a running sum:
select reg_id, client_id, reg_start, reg_end,
count(*) over (partition by client_id order by reg_start) - 1 as previous_reg
from registrations
order by reg_start desc;
Upvotes: 2
Reputation: 72185
In SQL Server you can use the following query:
SELECT [Reg ID], [Client ID], Reg_Start, Reg_End,
COUNT(*) OVER (PARTITION BY [Client ID] ORDER BY Reg_Start) - 1
FROM mytable
COUNT
, when applied with an ORDER BY
clause, returns the running total of records count. If this is available in Oracle, then it should return the value you want.
Upvotes: 1
Reputation: 1270653
You can do this with row_number()
:
select r.*,
(row_number() over (partition by client_id order by reg_start) - 1) as cnt
from registrations r;
Upvotes: 2