如何把一个父子结构的表拉成平面表

有个MSSQL表结构如下:

org_dept:部门(pk_dept:部门ID, name:部门名称, pk_fatherorg:上级部门ID)

根部门的上级部门ID是’~’

有两个方案:

方案一:用嵌套表方式生成视图;方案二:用函数实现传入ID传出各级部门,然后再展开

方案一代码:

alter view v_dept_flat
as
WITH Reordered_Dept AS (
    SELECT 
        pk_dept, 
        name,
        pk_fatherorg,
        CAST(name AS VARCHAR(8000)) AS name_1,
        CAST('' AS VARCHAR(8000)) AS name_2,
        CAST('' AS VARCHAR(8000)) AS name_3,
        CAST('' AS VARCHAR(8000)) AS name_4,
        CAST('' AS VARCHAR(8000)) AS name_5,
        CAST('' AS VARCHAR(8000)) AS name_6,
        CAST('' AS VARCHAR(8000)) AS name_7,
        CAST('' AS VARCHAR(8000)) AS name_8,
        CAST('' AS VARCHAR(8000)) AS name_9,
        CAST('' AS VARCHAR(8000)) AS name_10,
        CAST(pk_dept AS VARCHAR(20)) AS id_1,
        CAST('' AS VARCHAR(20)) AS id_2,
        CAST('' AS VARCHAR(20)) AS id_3,
        CAST('' AS VARCHAR(20)) AS id_4,
        CAST('' AS VARCHAR(20)) AS id_5,
        CAST('' AS VARCHAR(20)) AS id_6,
        CAST('' AS VARCHAR(20)) AS id_7,
        CAST('' AS VARCHAR(20)) AS id_8,
        CAST('' AS VARCHAR(20)) AS id_9,
        CAST('' AS VARCHAR(20)) AS id_10,
        1 AS level
    FROM org_dept
    WHERE pk_fatherorg = '~'
    and enablestate = 2 and hrcanceled = 'N'

    UNION ALL

    SELECT 
        d.pk_dept, 
        d.name,
        d.pk_fatherorg,
        r.name_1,
        CASE WHEN r.level = 1 THEN CAST(d.name as VARCHAR(8000)) ELSE r.name_2 END,
        CASE WHEN r.level = 2 THEN CAST(d.name as VARCHAR(8000)) ELSE r.name_3 END,        
        CASE WHEN r.level = 3 THEN CAST(d.name as VARCHAR(8000)) ELSE r.name_4 END,        
        CASE WHEN r.level = 4 THEN CAST(d.name as VARCHAR(8000)) ELSE r.name_5 END,        
        CASE WHEN r.level = 5 THEN CAST(d.name as VARCHAR(8000)) ELSE r.name_6 END,        
        CASE WHEN r.level = 6 THEN CAST(d.name as VARCHAR(8000)) ELSE r.name_7 END,        
        CASE WHEN r.level = 7 THEN CAST(d.name as VARCHAR(8000)) ELSE r.name_8 END,        
        CASE WHEN r.level = 8 THEN CAST(d.name as VARCHAR(8000)) ELSE r.name_9 END,        
        CASE WHEN r.level = 9 THEN CAST(d.name as VARCHAR(8000)) ELSE r.name_10 END,        
        r.id_1,
        CASE WHEN r.level = 1 THEN CAST(d.pk_dept as VARCHAR(20)) ELSE r.id_2 END,
        CASE WHEN r.level = 2 THEN CAST(d.pk_dept as VARCHAR(20)) ELSE r.id_3 END,        
        CASE WHEN r.level = 3 THEN CAST(d.pk_dept as VARCHAR(20)) ELSE r.id_4 END,        
        CASE WHEN r.level = 4 THEN CAST(d.pk_dept as VARCHAR(20)) ELSE r.id_5 END,        
        CASE WHEN r.level = 5 THEN CAST(d.pk_dept as VARCHAR(20)) ELSE r.id_6 END,        
        CASE WHEN r.level = 6 THEN CAST(d.pk_dept as VARCHAR(20)) ELSE r.id_7 END,        
        CASE WHEN r.level = 7 THEN CAST(d.pk_dept as VARCHAR(20)) ELSE r.id_8 END,        
        CASE WHEN r.level = 8 THEN CAST(d.pk_dept as VARCHAR(20)) ELSE r.id_9 END,        
        CASE WHEN r.level = 9 THEN CAST(d.pk_dept as VARCHAR(20)) ELSE r.id_10 END,        
        r.level + 1
    FROM org_dept d
    INNER JOIN Reordered_Dept r ON d.pk_fatherorg = r.pk_dept
    where enablestate = 2 and hrcanceled = 'N'

)

SELECT * FROM Reordered_Dept

方案二代码:

CREATE function [dbo].[fn_get_full_dept_info](@dept nvarchar(20))
RETURNS nvarchar(MAX) as
begin
    -- declare @dept nvarchar(20)
    declare @pk nvarchar(20)
    declare @name nvarchar(200)
    declare @id int
    declare @row int
    declare @pid nvarchar(20)
    declare @result nvarchar(MAX)

    DECLARE @array TABLE (
      id INT primary key identity(1,1)
      ,pk nvarchar(20)
      ,name nvarchar(200)
    );

    -- set @dept = '1001A11000000000201G'
    set @row = 1

    select @pk = pk_dept, @name = name, @pid = pk_fatherorg from org_dept where pk_dept = @dept
    insert into @array(pk,name) values(@pk, @name)
    while @pid <> '~' begin
        select @pk = pk_dept, @name = name, @pid = pk_fatherorg from org_dept where pk_dept = @pid
        insert into @array(pk,name) values(@pk, @name)
        set @row = @row + 1
    end
    
    set @result = ( select 1+@row - id as id,pk,name from @array order by id for json auto)

    return @result
end

函数的使用方法如下,由于函数返回的信息比较多,使用了JSON格式,在使用结果的时候,可以按需用JSON函数解析

select pk_dept,code,name
, JSON_VALUE(JSON_QUERY(dbo.fn_get_full_dept_info(pk_dept), CONCAT('$[', 0, ']')), '$.name') AS name
, JSON_VALUE(JSON_QUERY(dbo.fn_get_full_dept_info(pk_dept), CONCAT('$[', 1, ']')), '$.name') AS name
, JSON_VALUE(JSON_QUERY(dbo.fn_get_full_dept_info(pk_dept), CONCAT('$[', 2, ']')), '$.name') AS name
, JSON_VALUE(JSON_QUERY(dbo.fn_get_full_dept_info(pk_dept), CONCAT('$[', 3, ']')), '$.name') AS name
, JSON_VALUE(JSON_QUERY(dbo.fn_get_full_dept_info(pk_dept), CONCAT('$[', 4, ']')), '$.name') AS name
from org_dept