Sql 带CTE的分层数据

Sql 带CTE的分层数据,sql,sql-server,tsql,Sql,Sql Server,Tsql,如果答案已经发布,我很抱歉,但即使在搜索后我也无法找到答案 我有下表 CREATE TABLE [dbo].[emp]( [id] [int] NOT NULL, [name] [varchar](20) NULL, [mgrid] [int] NULL ) ON [PRIMARY] 有数据 INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (1, N'a', 0) INSERT [dbo].[emp] ([id], [

如果答案已经发布,我很抱歉,但即使在搜索后我也无法找到答案

我有下表

CREATE TABLE [dbo].[emp](
    [id] [int] NOT NULL,
    [name] [varchar](20) NULL,
    [mgrid] [int] NULL
) ON [PRIMARY]
有数据

INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (1, N'a', 0)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (2, N'a1', 1)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (3, N'a11', 2)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (4, N'a12', 2)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (5, N'a13', 2)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (6, N'a2', 1)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (7, N'a3', 1)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (8, N'a31', 7)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (9, N'a32', 7)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (10, N'b', 0)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (11, N'b1', 10)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (12, N'b2', 10)
我想要下面的输出

a
    a1
        a11
        a12
        a13
    a2
    a3
        a31
        a32
b
    b1
    b2
这在SQL Server中可能吗?

您可以使用CTE(Comnon表表达式来实现这一点)

with CTE as
(
  select *
    , level = 1
  from emp
  where mgrid = 0
  union all
  select emp.id,
    name = cast(space((level) * 3) + emp.name as varchar(20)),
    emp.mgrid,
    level = level + 1
  from emp
    inner join CTE on CTE.id = emp.mgrid
)
select name
from CTE
order by ltrim(name)
检查此示例代码:

declare @emp table(
    [id] [int] NOT NULL,
    [name] [varchar](20) NULL,
    [mgrid] [int] NULL
) 


INSERT @emp ([id], [name], [mgrid]) VALUES (1, N'a', 0)
INSERT @emp ([id], [name], [mgrid]) VALUES (2, N'a1', 1)
INSERT @emp ([id], [name], [mgrid]) VALUES (3, N'a11', 2)
INSERT @emp ([id], [name], [mgrid]) VALUES (4, N'a12', 2)
INSERT @emp ([id], [name], [mgrid]) VALUES (5, N'a13', 2)
INSERT @emp ([id], [name], [mgrid]) VALUES (6, N'a2', 1)
INSERT @emp ([id], [name], [mgrid]) VALUES (7, N'a3', 1)
INSERT @emp ([id], [name], [mgrid]) VALUES (8, N'a31', 7)
INSERT @emp ([id], [name], [mgrid]) VALUES (9, N'a32', 7)
INSERT @emp ([id], [name], [mgrid]) VALUES (10, N'b', 0)
INSERT @emp ([id], [name], [mgrid]) VALUES (11, N'b1', 10)
INSERT @emp ([id], [name], [mgrid]) VALUES (12, N'b2', 10);


with cte (id,name, MGRID) as
(
    select id, name,MGRID
    from @emp
    union all
    select c.id, c.name, c.MGRID
    from @emp c
    inner join cte p
        on c.mgrid = P.id
)


SELECT Distinct * FROM CTE

可以在最后一行中使用“”而不是“+”来填充字符串

with t as
(
  select id,name,mgrid,1 as level,cast(name as varchar(max)) as path 
         from emp where mgrid=0
  union all 
  select emp.id,emp.name,emp.mgrid, t.level+1 as level, 
         t.path+cast(emp.name as varchar(max)) as path

  from emp
  join t on emp.mgrid=t.id
)

select replicate('+', level)+name from t order by path

查询:

DECLARE @temp TABLE
(
    [id] [int] NOT NULL,
    [name] [varchar](20) NULL,
    [mgrid] [int] NULL
)

INSERT INTO @temp ([id], [name], [mgrid])
VALUES 
    (1, N'a', 0), (2, N'a1', 1),
    (3, N'a11', 2), (4, N'a12', 2),
    (5, N'a13', 2), (6, N'a2', 1),
    (7, N'a3', 1), (8, N'a31', 7),
    (9, N'a32', 7), (10, N'b', 0),
    (11, N'b1', 10), (12, N'b2', 10)

DECLARE @out VARCHAR(MAX) = ''

;WITH cte AS 
(
    SELECT *, Lvl = 0, nn = CAST(name AS VARCHAR(MAX))
    FROM @temp
    WHERE mgrid = 0

    UNION ALL

    SELECT t.*, c.Lvl + 1, nn = CAST(REPLICATE('   ', c.Lvl + 1) + t.name AS VARCHAR(MAX))
    FROM @temp t
    JOIN cte c ON c.id = t.mgrid
)
SELECT @out = (
    SELECT nn + CHAR(13)
    FROM cte
    ORDER BY LTRIM(nn)
    FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')

PRINT @out
a
   a1
      a11
      a12
      a13
   a2
   a3
      a31
      a32
b
   b1
   b2
输出:

DECLARE @temp TABLE
(
    [id] [int] NOT NULL,
    [name] [varchar](20) NULL,
    [mgrid] [int] NULL
)

INSERT INTO @temp ([id], [name], [mgrid])
VALUES 
    (1, N'a', 0), (2, N'a1', 1),
    (3, N'a11', 2), (4, N'a12', 2),
    (5, N'a13', 2), (6, N'a2', 1),
    (7, N'a3', 1), (8, N'a31', 7),
    (9, N'a32', 7), (10, N'b', 0),
    (11, N'b1', 10), (12, N'b2', 10)

DECLARE @out VARCHAR(MAX) = ''

;WITH cte AS 
(
    SELECT *, Lvl = 0, nn = CAST(name AS VARCHAR(MAX))
    FROM @temp
    WHERE mgrid = 0

    UNION ALL

    SELECT t.*, c.Lvl + 1, nn = CAST(REPLICATE('   ', c.Lvl + 1) + t.name AS VARCHAR(MAX))
    FROM @temp t
    JOIN cte c ON c.id = t.mgrid
)
SELECT @out = (
    SELECT nn + CHAR(13)
    FROM cte
    ORDER BY LTRIM(nn)
    FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')

PRINT @out
a
   a1
      a11
      a12
      a13
   a2
   a3
      a31
      a32
b
   b1
   b2

你可以在它前面加一个空字符串。这是打印输出。或者这些是不同的列?您想将此用于某些特定的进一步处理吗?
按ltrim(名称)排序
仅在a1、a11、a12为真名时才有效。@RaviSingh,没错。。。另一种方法是动态构建层次路径,就像@valex的答案一样;因为他已经这样做了,所以我将保留我的身份,并将信用留给他。这不会像我更改数据那样起作用整个事情都会一团糟,只要尝试使用2个gice名称z2As更新记录id,@valex提供的解决方案解决了这一问题,您应该进一步调查他的答案。thx我接受这一点回答,但我需要写“选择不同于”CTE@Dhaval:谢谢你指出。。我很高兴我的回答解决了你的问题