如何避免重叠深度interval-ranges-when-using-a-grouping-clause

时间:2014-12-04 07:56:06

标签: sql sql-server-2008

我需要根据相同代码的深度间隔分组生成汇总表。我尝试了一个简单的group by子句,其中包含Minimum From_Depth和Meximum To_Depth,但它消除了重叠的更改。以下是示例:

Create Table #Lithology (
      Hole_ID varchar(10)
    , mFrom int
    , mTo int
    , Strat varchar(10)
    ,Strand varchar(10)
)

insert into #Lithology (Hole_ID, mFrom, mTo, Strat, Strand ) values ('MD4803', 0, 2, 'CzD3', 'ALU');
insert into #Lithology (Hole_ID, mFrom, mTo, Strat, Strand ) values ('MD4803', 2, 4, 'CzD3', 'ALU');
insert into #Lithology (Hole_ID, mFrom, mTo, Strat, Strand ) values ('MD4803', 4, 6, 'CzD3', 'SCR');
insert into #Lithology (Hole_ID, mFrom, mTo, Strat, Strand ) values ('MD4803', 6, 8, 'CzD3', 'SCR');
insert into #Lithology (Hole_ID, mFrom, mTo, Strat, Strand ) values ('MD4803', 6, 8, 'CzD3', 'SCR');
insert into #Lithology (Hole_ID, mFrom, mTo, Strat, Strand ) values ('MD4803', 8, 10, 'CzD2', 'CIDW');
insert into #Lithology (Hole_ID, mFrom, mTo, Strat, Strand ) values ('MD4803', 10, 12, 'CzD2', 'CIDW');
insert into #Lithology (Hole_ID, mFrom, mTo, Strat, Strand ) values ('MD4803', 12, 14, 'CzD2', 'CIDO');
insert into #Lithology (Hole_ID, mFrom, mTo, Strat, Strand ) values ('MD4803', 14, 16, 'CzD2', 'CIDW');
insert into #Lithology (Hole_ID, mFrom, mTo, Strat, Strand ) values ('MD4803', 16, 18, 'CzD2', 'CIDW');
insert into #Lithology (Hole_ID, mFrom, mTo, Strat, Strand ) values ('MD4803', 18, 20, 'NAM', 'TNAM');
insert into #Lithology (Hole_ID, mFrom, mTo, Strat, Strand ) values ('MD4803', 20, 22, 'NAM', 'TNAM');
insert into #Lithology (Hole_ID, mFrom, mTo, Strat, Strand ) values ('MD4803', 22, 24, 'NAM', 'SNAM');
insert into #Lithology (Hole_ID, mFrom, mTo, Strat, Strand ) values ('MD4803', 24, 26, 'NAM', 'SNAM');
insert into #Lithology (Hole_ID, mFrom, mTo, Strat, Strand ) values ('MD4803', 26, 28, 'NAM', 'SONAM');
insert into #Lithology (Hole_ID, mFrom, mTo, Strat, Strand ) values ('MD4803', 28, 30, 'NAM', 'SONAM');
insert into #Lithology (Hole_ID, mFrom, mTo, Strat, Strand ) values ('MD4803', 30, 32, 'NAM', 'SNAM');
insert into #Lithology (Hole_ID, mFrom, mTo, Strat, Strand ) values ('MD4803', 32, 34, 'NAM', 'SNAM');
insert into #Lithology (Hole_ID, mFrom, mTo, Strat, Strand ) values ('MD4803', 34, 36, 'NAM', 'NNAM');
insert into #Lithology (Hole_ID, mFrom, mTo, Strat, Strand ) values ('MD4803', 36, 38, 'NAM', 'NNAM');


select Hole_ID
, min(mFrom) StartDepth
, max( mTo) EndDepth
, Strat, Strand
from #Lithology
group by Hole_ID, Strat, Strand
order by MIN(mFrom)

它返回以下重叠深度范围的结果。

Hole_ID StartDepth  EndDepth    Strat   Strand
MD4803  0           4           CzD3    ALU
MD4803  4           8           CzD3    SCR
MD4803  8           18          CzD2    CIDW
MD4803  12          14          CzD2    CIDO
MD4803  18          22              NAM TNAM
MD4803  22          34          NAM SNAM
MD4803  26          30          NAM SONAM
MD4803  34          38          NAM NNAM

预期结果如下,没有重叠间隔:

Hole_ID StartDepth  EndDepth    Strat   Strand
MD4803  0           4           CzD3    ALU
MD4803  4           8           CzD3    SCR
MD4803  8           12          CzD2    CIDW
MD4803  12          14          CzD2    CIDO
MD4803  14          18          CzD2    CIDW
MD4803  18          22          NAM TNAM
MD4803  22          26          NAM SNAM
MD4803  26          30          NAM SONAM
MD4803  30          34          NAM SNAM
MD4803  34          38          NAM NNAM

任何建议都将不胜感激。 感谢。

1 个答案:

答案 0 :(得分:0)

使用递归CTE识别群组的解决方案:

;WITH lithCTE
AS
(
    -- number the rows for each hole id (in case any data in the sequence is missing)
    SELECT * ,
    ROW_NUMBER() OVER (PARTITION BY Hole_Id ORDER BY mFrom
                        ) AS rn
    FROM #Lithology
)
,retCTE
AS
(
    --starting from the top of each hole in the dataset, identify groups
    SELECT Hole_Id, mFrom, mTo, Strat,Strand, rn, 1 AS grp
    FROM lithCTE
    WHERE rn = 1

    UNION ALL

    SELECT l.Hole_Id, l.mFrom, l.mTo, l.Strat,l.Strand, l.rn, 
    CASE    WHEN r.Hole_Id = l.Hole_id  
            AND r.strat = l.strat 
            AND r.Strand = l.Strand  
            THEN r.grp ELSE r.grp + 1 END AS grp
    FROM retCTE AS r
    JOIN lithCTE AS l
    ON l.hole_id = r.hole_id AND l.rn = r.rn + 1
)
SELECT Hole_ID
, MIN(mFrom) StartDepth
, MAX( mTo) EndDepth
, Strat, Strand
FROM retCTE
GROUP BY Hole_ID, Strat, Strand,grp
ORDER BY Hole_ID,StartDepth

可能有一个更简单的解决方案,但目前它还没有找到我。