简体   繁体   中英

SQL [Oracle]: Count number of previous records with same client ID

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!

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;

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;

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.

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

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