如何使用纯SQL合并连续相同GR分组的记录并保留时间顺序
Your core issue here is that your original query groups all records with the same GR together, regardless of whether they're interrupted by other GR values. What you need instead is to group consecutive sequences of the same GR—this is a classic "gap and island" problem in SQL.
Here's a pure SQL solution that works across most modern databases (PostgreSQL, MySQL 8.0+, SQL Server, Oracle, etc.):
WITH ranked_records AS ( SELECT GR, I, VON, BIS, -- Mark when the GR changes from the previous row CASE WHEN GR = LAG(GR) OVER (ORDER BY VON) THEN 0 ELSE 1 END AS grp_change FROM table_test ), blocked_records AS ( SELECT GR, I, VON, BIS, -- Create a unique ID for each consecutive GR block SUM(grp_change) OVER (ORDER BY VON ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS block_id FROM ranked_records ) SELECT GR, FIRST_VALUE(I) OVER (PARTITION BY block_id ORDER BY VON) AS I, MIN(VON) AS VON, MAX(BIS) AS BIS FROM blocked_records GROUP BY block_id, GR ORDER BY VON;
How this works:
ranked_recordsCTE:- Uses
LAG(GR) OVER (ORDER BY VON)to fetch theGRvalue from the immediately preceding record (ordered by your start dateVON). - The
grp_changeflag is set to1whenever the current row'sGRis different from the previous row, marking the start of a new consecutive block.
- Uses
blocked_recordsCTE:- Uses a running total (
SUM(grp_change) OVER (...)) to assign a uniqueblock_idto each consecutive sequence of the sameGR. Every timegrp_changeis1, the total increments, creating a new block.
- Uses a running total (
Final SELECT:
- Groups by
block_id(each representing a consecutive GR sequence) andGR. - Uses
FIRST_VALUE(I)to get theIvalue from the first record in the block (matches your expected output wherecis kept for the merged GR=1 block). - Takes the minimum
VONand maximumBISto merge the time interval for the block.
- Groups by
Testing with your sample data:
Running this query on your table_test will produce exactly the expected result:
| GR | I | VON | BIS |
|---|---|---|---|
| 1 | a | 1 | 2 |
| 2 | b | 2 | 3 |
| 1 | c | 3 | 5 |
| 3 | e | 5 | 6 |
Why your original query failed:
Your original query used PARTITION BY GR, which grouped all GR=1 records together (even the ones separated by GR=2). This is why it merged the first, third, and fourth rows into a single block, which wasn't what you wanted. The gap-and-island approach fixes this by only grouping consecutive same-GR records.
内容的提问来源于stack exchange,提问作者sers

