Search code examples
sqlsql-servert-sqlgroupingrow-number

SQL Server Grouping unrelated records according to row value


How can I group repeating records?

I have a single column that denotes whether a record is a start, end or a detail record. Detail Records are records that exist after a start record and before a end record.

I want to group these records together with a unique identifier so that each time there is a end record the next series of records get a new group id.

I've tried a series of self joins, sub queries and cte's Without building a custom function, view or CTE I'm hoping to build this in a single select query.

Any advice or pointers much appreciated.

Example before solution:

--------------------------------------------------
| ID      | RecordType    |  SomeValue
--------------------------------------------------
|001      | Start record  |  some header info
|002      | Detail Record |  value
|003      | Detail Record |  value
|004      | Detail Record |  value
|005      | End Record    |  some other header info
|006      | Start Record  |  some header info
|007      | Detail Record |  Value
|008      | End  Record   |  some other header info

What I've trying to achieve:

------------------------------------------------------------------
| ID      | RecordType    |  SomeValue             | RecordGroup
------------------------------------------------------------------
|001      | Start record  |  some header info      | 001
|002      | Detail Record |  value                 | 001
|003      | Detail Record |  value                 | 001
|004      | Detail Record |  value                 | 001
|005      | End Record    |  some other header info| 001
|006      | Start Record  |  some header info      | 002
|007      | Detail Record |  Value                 | 002
|008      | End  Record   |  some other header info| 002

Solution

  • You can use the LAG function and running SUM. The following assumes that there is no partitioning and rows are ordered by ID:

    SELECT ID, RecordType, SomeValue,
           SUM(chg) OVER (ORDER BY ID) AS grp
    FROM (
        SELECT ID, RecordType, SomeValue,
               CASE WHEN LAG(RecordType) OVER (ORDER BY ID) IN ('Start record', 'Detail Record') THEN 0 ELSE 1 END AS chg
        FROM t
    ) cte1
    

    Demo on DB Fiddle