根据列对表中的数据行进行分组

时间:2015-07-17 08:35:34

标签: sql sql-server tsql

我想用SQL实现以下任何人都可以帮助:

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

应该成为:

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

基本上想要为相同的连续RockSymbol分组数据,其中结果中连续块的第一个记录的TOP变为分组记录的TOP,而连续块的最后一个记录的BOTTOM变为分组的BOTTOM记录。

连续的RockSymbol记录数量可能会有所不同。

3 个答案:

答案 0 :(得分:0)

更新回答 - 考虑我们可以连续多行使用相同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小提琴链接http://sqlfiddle.com/#!6/dc3c3/3

编辑:旧答案 - 仅用于了解解决方案的演变

  

如果你可以改变原始表,那么可能会更新   声明

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 
     

然后删除额外的行

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
     

如果您无法更新表格,请使用临时表或嵌套SELECT   查询如下

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链接都在这里   http://sqlfiddle.com/#!6/e1148/1/0和   http://sqlfiddle.com/#!6/e1148/7

答案 1 :(得分:0)

你需要做这样的事情来实现你正在寻找的东西:

Select [TOP], Case when Rocksymbol = lag(Rocksymbol,1,-1) over (order by [TOP]) then lag([TOP],1,-1) over (order by [TOP]) else -1 end as match into #foobar2
from #foobar 

select Min(f1.[TOP]) [TOP], Max(f1.Bottom) Bottom, f1.Rocksymbol
from #foobar f1
Left join #foobar2 f2 on f1.[TOP] = f2.match
Left join #foobar2 f3 on f1.[TOP] = f3.[TOP]
Group by Case when f2.match <> -1 then f1.[TOP] else case when f3.match <> -1 then f3.match else f3.[TOP] end end, Rocksymbol
order by [TOP]

SQL的小提琴就在这里:http://sqlfiddle.com/#!6/b2ef2/2/0

答案 2 :(得分:0)

select  IDENTITY(int,1,1) as id ,* into #temp from (
select 0 as 'top', 5 as botton,'l' as rocksymble union all
select 5, 10,'l' union all
select 10, 15,'ml' union all
select 15, 20,'ml' union all
select 20, 25,'s' union all
select 25, 30,'ml' union all
select 30, 35,'s'  union all
select 35, 40,'ml' union all
select 40, 45,'ml' union all
select 45, 50,'ml'
) as  a

select a.*, b.id as bid into #temp1 from #temp a
left join #temp b
on a.[top] = b.[botton]
and a.rocksymble = b.rocksymble


select a.id,a.rocksymble,a.bid, count(case when b.bid IS null then 1 else null end) grpid into  #temp2  from #temp1 a , #temp1 b
where b.id <= a.id
group by a.id,a.rocksymble,a.bid
order by a.id

select min(b.[top]),max(b.botton),b.rocksymble from #temp2 a
join #temp1 b
on a.id = b.id
group by b.rocksymble, a.grpid