如何对父子行进行分组(TSQL)

时间:2016-08-23 08:15:33

标签: tsql sql-server-2008-r2 grouping

我有一个SQL表,其中一些事务处于父子关系中。但该关系仅由行和类型列确定。没有其他参考。我必须建立这个参考。

DECLARE @tmp TABLE (line INT, type CHAR(1), product VARCHAR(30))
INSERT @tmp VALUES
              ( 1,' ','22411')
             ,( 2,' ','22413')
             ,( 3,'P','27050')
             ,( 4,'C','22492')
             ,( 5,'C','22493')
             ,( 6,'C','22490')
             ,( 7,' ','22410')
             ,( 8,' ','22511')
             ,( 9,'P','27051')
             ,(10,'C','22470')
             ,(11,'C','22471')
             ,(12,'C','22473')
             ,(13,'C','22474')
             ,(14,' ','22015')
             ,(15,' ','22167')
             ,(16,' ','12411')
             ,(17,' ','22500')

第3行是父产品。第4行到第6行是子行。 第9行是另一个母产​​品。第10行到第13行是子行。

所需的输出是这样的,其中父子行被分组:

line|type|product|group
1   |    |22411  |1
2   |    |22413  |2
3   |P   |27050  |3
4   |C   |22492  |3
5   |C   |22493  |3
6   |C   |22490  |3
7   |    |22410  |7
8   |    |22511  |8
9   |P   |27051  |9
10  |C   |22470  |9
11  |C   |22471  |9
12  |C   |22473  |9
13  |C   |22474  |9
14  |    |22015  |14
15  |    |22167  |15
16  |    |12411  |16
17  |    |22500  |17

如何在没有光标的情况下实现这一目标?

2 个答案:

答案 0 :(得分:2)

如果输入始终有效,您可以使用以下查询。

SELECT *, RANK() OVER(ORDER BY gid) AS [group]
FROM 
(
    SELECT *, SUM(CASE WHEN type = 'C' AND (prev = 'P' OR prev = 'C') THEN 0 ELSE 1 END) OVER(ORDER BY line) AS gid
    FROM 
    (
        SELECT *, LAG(type) OVER(ORDER BY line) AS prev
        FROM @tmp
    ) AS withPreviouLine
) AS grouped

它无法处理连续的C'没有' P'。从SQL SERVER 2012开始添加LAG。

答案 1 :(得分:1)

这几乎适用于所有版本的SQL Server,因为您没有指定正在使用的版本。

但是如果你至少使用SQL Server 2012,那么你可以使用@ qxg的解决方案,因为它更简单。

这是您需要的代码,虽然它不是单个查询,但它可以为您提供所需的结果:

CREATE TABLE #tmp (line INT, type CHAR(1), product VARCHAR(30))
INSERT #tmp VALUES ( 1,' ','22411')
             ,( 2,' ','22413')
             ,( 3,'P','27050')
             ,( 4,'C','22492')
             ,( 5,'C','22493')
             ,( 6,'C','22490')
             ,( 7,' ','22410')
             ,( 8,' ','22511')
             ,( 9,'P','27051')
             ,(10,'C','22470')
             ,(11,'C','22471')
             ,(12,'C','22473')
             ,(13,'C','22474')
             ,(14,' ','22015')
             ,(15,' ','22167')
             ,(16,' ','12411')
             ,(17,' ','22500')
select t1.*
    , case
        when t1.type = 'C'
            and t3.type = ''
                then 'G'
        when t1.type = 'P' or t1.type = 'C'
            then 'G'
        else 'N'
    end [same_group]
into #tmp2
from #tmp t1
    left join #tmp t2 on t1.line = t2.line + 1
    left join #tmp t3 on t1.line = t3.line - 1
order by t1.line

select *
    , case 
          when t.type <> '' 
              then (select max(line) 
                    from #tmp2 
                     where same_group = 'G' 
                         and type = 'P' 
                         and line <= t.line) 
        else t.line 
    end [group_id]
from #tmp2 t
order by line

您可能会将其重构为单个查询,但目前我没有时间这样做。