生成列表编号

时间:2016-11-15 04:07:30

标签: sql sql-server

我的桌子看起来像这样:

+-------+--------+--------+
| Grp   | Party  | Member |
+-------+--------+--------+
| FC    | Party1 | Tom    |
| FC    | Party1 | Alice  |
| FC    | Party2 | John   |
| FC    | Party3 | Mary   |
| GC    | Party2 | Anna   |
| GC    | Party4 | Alex   |
| GC    | Party5 | Diana  |
+-------+--------+--------+

我想将表格转换为如下列表:

+-------+--------+
|  ID   |  Text  |
+-------+--------+
| 1     | FC     |
| 1.1   | Party1 |
| 1.1.1 | Tom    |
| 1.1.2 | Alice  |
| 1.2   | Party2 |
| 1.2.1 | John   |
| 1.3   | Party3 |
| 1.3.1 | Mary   |
| 2     | GC     |
| 2.1   | Party2 |
| 2.1.1 | Anna   |
| 2.2   | Party4 |
| 2.2.1 | Alex   |
| 2.3   | Party5 |
| 2.3.1 | Diana  |
+-------+--------+

我已尝试rolluprow_number,但结果仍然远离我想要的

;with ctx as (
    select * from @test
    group by rollup(Grp, Party, Member)
)
select row_number() over (partition by grp order by grp, party, member) as g,
        row_number() over (partition by grp, party order by grp, party, member) as p,
        row_number() over (partition by grp, party, member order by grp, party, member) as m,
        grp, party, member
from ctx
where grp is not null
order by grp, party, member

提前致谢。

修改
这是生成表的SQL,希望这可以帮助

declare @test table (Grp varchar(10), Party varchar(10), Member varchar(20))

insert into @test values ('FC', 'Party1', 'Tom')
insert into @test values ('FC', 'Party1', 'Alice')
insert into @test values ('FC', 'Party2', 'John')
insert into @test values ('FC', 'Party3', 'Mary')
insert into @test values ('GC', 'Party2', 'Anna')
insert into @test values ('GC', 'Party4', 'Alex')
insert into @test values ('GC', 'Party5', 'Diana')

4 个答案:

答案 0 :(得分:2)

这是一种方式

;WITH cte
     AS (SELECT Dense_rank()OVER (ORDER BY grp)    AS g,
                Dense_rank()OVER (partition BY grp ORDER BY party)  AS p,
                Row_number()OVER (partition BY grp, party ORDER BY member) AS m,
                grp,
                party,
                member
         FROM   @test
         WHERE  grp IS NOT NULL) 
SELECT DISTINCT grp,
                Cast(g AS VARCHAR(10)) AS [Text]
FROM   cte
UNION ALL
SELECT DISTINCT party,
                Concat(g, '.', p)
FROM   cte
UNION ALL
SELECT member,
        Concat(g, '.', p, '.', m)
FROM   cte
ORDER  BY [Text] 

您需要使用DENSE_RANK让父母正确生成层次结构编号。如果您在Member中也有重复内容,请将ROW_NUMBER更改为DENSE_RANK内的CTE,并在最终的select查询中添加不同内容

注意:如果您使用的内容少于SQL SERVER 2012,请使用+运算符进行连接,而不是CONCAT

答案 1 :(得分:2)

这使用DENSE_RANKID获取正确的编号。然后CROSS APPLY to unpivot数据并标记哪一行适用于GrpPartyMember。最后使用WHERE仅过滤您需要的行:

WITH CteUnpivot AS(
    SELECT *
    FROM (
        SELECT *,
            rnGrp       = DENSE_RANK() OVER(ORDER BY Grp),
            rnParty     = DENSE_RANK() OVER(PARTITION BY Grp ORDER BY Party),
            rnMember    = ROW_NUMBER() OVER(PARTITION BY Grp, Party ORDER BY Member)
        FROM test
    ) t
    CROSS APPLY(VALUES
        ('Grp', Grp),
        ('Party', Party),
        ('Member', Member)
    ) x (col, [Text])
)
SELECT
    ID = CASE
            WHEN col = 'Grp' THEN CAST(rnGrp AS VARCHAR(3))
            WHEN col = 'Party' THEN CAST(rnGrp AS VARCHAR(3)) + '.' + CAST(rnParty AS VARCHAR(3))
            WHEN col = 'Member' THEN CAST(rnGrp AS VARCHAR(3)) + '.' + CAST(rnParty AS VARCHAR(3)) + '.' + CAST(rnMember AS VARCHAR(3))
         END,
    [Text]
FROM CteUnpivot
WHERE
    (col = 'Grp' AND rnParty = 1 AND rnMember = 1)
    OR (col = 'Party' AND rnMember = 1)
    OR (col = 'Member')
ORDER BY rnGrp, rnParty, rnMember;

ONLINE DEMO

如果订单与Member无关,请将rnMember替换为:

rnMember    = ROW_NUMBER() OVER(PARTITION BY Grp, Party ORDER BY (SELECT NULL))

ONLINE DEMO

答案 2 :(得分:1)

坦率地说,我不会在数据库级别这样做。相反,我会确保输出按{Grp,Party,Member}排序,然后分配" Id"显示数据时,单次传递的值。

但是,如果您出于某种原因决定在数据库服务器中执行此操作,则可以使用dense_rank()函数获取每个ID:

;with cte as (
  select dense_rank() over (order by Grp) id0,
    dense_rank() over (partition by Grp order by Party) id1,
    dense_rank() over (partition by Grp, Party order by Member) id2,
    Grp, Party, Member
  from Table1
), grps as (select distinct id0, Grp from cte),
parties as (select distinct id0, id1, Party from cte),
members as (select distinct id0, id1, id2, Member from cte),
[list] as (
  select cast(id0 as varchar(50)) as id, Grp as [Text] from grps
  union all
  select cast(id0 as varchar(50)) + '.' + cast(id1 as varchar(50)), Party from parties
  union all
  select cast(id0 as varchar(50)) + '.' + cast(id1 as varchar(50)) + '.' + cast(id2 as varchar(50)), Member from members
)
select id, [Text]
from [list]
order by id

答案 3 :(得分:1)

此选项不使用DENSE_RANK()ROW_NUMBER(),但与发布的其他答案基本相似。

With grps As (
    Select Grp, GrpNo = Row_Number() Over (Order By Grp)
      From (Select Distinct Grp From MyTable) As MyTable),
parties As (
    Select MyTable.Grp, MyTable.Party, grps.GrpNo, PrtyNo = Row_Number() Over (Partition By MyTable.Grp Order By MyTable.Party)
      From (Select Distinct Grp, Party From MyTable) As MyTable
      Join grps On MyTable.Grp = grps.Grp),
members As (
    Select MyTable.Grp, MyTable.Party, MyTable.Member,
        parties.GrpNo, parties.PrtyNo, MbrNo = Row_Number() Over (Partition By MyTable.Grp, MyTable.Party Order By #groups.Member)
      From MyTable
      Join parties On MyTable.Grp = parties.Grp And MyTable.Party = parties.Party)
Select ID = Convert(char(5), GrpNo), 
    [Text] = Grp 
  From grps
Union All
Select ID = Convert(char(1), GrpNo) + '.' + Convert(char(1), PrtyNo),
    [Text] = Party
  From parties
Union All
Select ID = Convert(char(1), GrpNo) + '.' + Convert(char(1), PrtyNo) + '.' + Convert(char(1), MbrNo),
    [Text] = Member
  From members;