Skip to content
Advertisement

Group rows of data from table based on a column

I want to achieve the below using SQL can anyone please help:

TOP     BOTTOM  Rocksymbol
 0        5         l
 5        10        l
10        15        ml
15        20        ml
20        25        ml
25        30        s
30        35        ml
35        40        ml
40        45        s

Should become:

TOP BOTTOM  Rocksymbol
 0    10        l
10    25        ml
25    30        s
30    40        ml
40    45        s

Basically wanting to group the data for same consecutive RockSymbol, where in the result the TOP of first record of the consecutive block becomes the TOP of the grouped record and the BOTTOM of last record of the consecutive block becomes the BOTTOM of the grouped record.

The number of consecutive RockSymbol records can vary.

Advertisement

Answer

Updated answer – considering situation where we can have multiple consecutive rows with same RockSymbol.

SELECT
  MIN([top]) as [top],
  MAX(bottom) as bottom,
  RockSymbol
FROM
(
  SELECT
    ROW_NUMBER() OVER (ORDER BY [top]) rowid,
    ROW_NUMBER() OVER (PARTITION BY RockSymbol ORDER BY [top]) seqid
    ,*
  FROM
    [dbo].[tbl]
) tempt
GROUP BY
  RockSymbol,
  rowid - seqid
ORDER BY 
[top]

SQl fiddle link http://sqlfiddle.com/#!6/dc3c3/3

Edit: Old answeronly for the purpose of understanding the evolution of solution

If you can mutate original table then probably update statement

UPDATE A
SET A.[TOP]=B.[TOP]
FROM
[dbo].[tbl] A INNER JOIN [dbo].[tbl] B ON A.[TOP]=B.BOTTOM AND A.RockSymbol=B.RockSymbol 

followed by removal of extra rows

DELETE FROM   [dbo].[tbl] FROM [dbo].[tbl] B LEFT JOIN
( 
SELECT ROW_NUMBER() OVER(PARTITION BY [Top] ORDER BY Bottom DESC) AS "Rank", [TOP], BOTTOM, RockSymbol FROM [dbo].[tbl]) A 
ON A.[TOP]=B.[Top] AND A.[Bottom]=B.[Bottom] AND A.RockSymbol=B.RockSymbol
WHERE A.Rank>1

If you cannot update table please use a temp table or nested SELECT query like below

SELECT Q.[TOP], MAX(Q.BOTTOM) as BOTTOM,Q.RockSymbol  FROM
(SELECT 
ISNULL(B.[TOP],A.[TOP]) AS [TOP], 
A.BOTTOM, 
A.RockSymbol
FROM
[dbo].[tbl] A LEFT JOIN [dbo].[tbl] B ON A.[TOP]=B.BOTTOM AND A.RockSymbol=B.RockSymbol) Q
GROUP BY Q.[TOP], Q.RockSymbol

Sql fiddles link for both solution are here http://sqlfiddle.com/#!6/e1148/1/0 and http://sqlfiddle.com/#!6/e1148/7

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement