路径表中的附加列表

时间:2016-07-20 10:32:32

标签: sql sql-server

我有一张存储员工及其部门的表格。部门表示组织层次结构中的完整路径:

表名: SourceTable

|----------------------------------------------------------------------|
  Employee              Department
|----------------------------------------------------------------------|
   John D.              Organization/Department1/Department2
   Alexey N.            Organization/Department1/Deparment2/Department3
   Alan Z.              Organization/Department1
   Peter P.             Organization/Department4
   Zara N.              Organization/Department4/Department5
|----------------------------------------------------------------------|

我需要规范化这个表并创建两个新表,如下所示:

表:员工

|--------------------------------------------|
  Name                 DepartmentId
|--------------------------------------------|
  John D.              3
  Alexey N.            4
  Alan Z.              2
  Peter P.             5
  Zara N.              6

| -------------------------------------------- | < / p>

表名:部门

|--------------------------------------------|
  Id           ParentId          Name
|--------------------------------------------|
  1               null           Organization
  2               1              Department1
  3               2              Department2
  4               3              Department3
  5               1              Department4
  6               5              Department5
|-------------------------------------------|

我应该使用哪些查询?

提前致谢。

2 个答案:

答案 0 :(得分:0)

此处没有单一查询。

让我们先创建设置:

declare @t table (Employee varchar(10), Department varchar(100))
insert @t values
(   'John D.'   ,           'Organization/Department1/Department2'),
(   'Alexey N.' ,           'Organization/Department1/Department2/Department3'),
(   'Alan Z.'   ,           'Organization/Department1'),
(   'Peter P.'  ,           'Organization/Department4'),
(   'Zara N.'   ,           'Organization/Department4/Department5')

declare @d table (Id int identity(1,1), ParentId int, Name varchar(20))

declare @e table (Name varchar(10), DepartmentId int)

我们还需要一个函数来解析字符串reporesenting路径(我们在这里需要数字表,请在SO中搜索如何创建和填充一个的说明):

create function dbo.splitstrings_numbers
(
    @list       nvarchar(max),
    @delimiter  nvarchar(5)
)
returns table
with schemabinding
as
    return
    (
        select number, item = substring(@list, number,
            charindex(@delimiter, @list + @delimiter, number) - number)
        from dbo.numbers
        where number <= convert(int, len(@list))
            and substring(@delimiter + @list, number, len(@delimiter)) = @delimiter
    );

现在我们可以解析路径(进入临时表,我们重用它):

select *, 0 as rn 
into #t 
from @t
outer apply [dbo].[splitstrings_numbers] (department, '/')

create index IX__t__employee_number on #t (employee, number)

;with x as (
    select *, row_number() over (partition by employee order by number desc) rn2
    from #t
)
update x set rn = rn2

从现在开始很容易:)

insert @d (name)
select distinct item from #t


;with x as (
    select d.parentid, d3.id as new_parentid
    from @d d 
    join (select distinct item, lag(item) over(partition by employee order by rn desc) as parent from #t) d2 on d2.item = d.name
    join @d d3 on d2.parent = d3.name
)
update x set parentid = new_parentid

insert @e
select #t.employee, d.id departmentid
from #t
join @d d on #t.item = d.name and #t.rn = 1

select * from @d
select * from @e

答案 1 :(得分:0)

假设部门名称在整个组织中是唯一的。 样本数据

select Employee, Department
into #sample_data
from (
    values
         ('John D.  ','Organization/Department1/Department2'),
         ('Alexey N.','Organization/Department1/Department2/Department3'),
         ('Alan Z.  ','Organization/Department1'),
         ('Peter P. ','Organization/Department4'),
         ('Zara N.  ','Organization/Department4/Department5')
    ) t(Employee, Department);

使用Jeff Moden的DelimitedSplit8K(或您选择的任何其他拆分器)拆分路径。它生成编号的项目列表。

select Department as path, d.*
into #tmp
from #sample_data
cross apply dbo.DelimitedSplit8K(Department,'/') d;

部门

select Department = item,
    id = row_number() over (order by item),
    parent_id=null
into #deps
from (
    select distinct item  
    from #tmp) t;

拥有dept id的员工

select Employee, 
   id = row_number() over (order by Employee),
   dep_id = d.id
into #emps
from #sample_data sd
join #deps d on sd.department like '%'+d.Department;

现在是adjency

update d
set parent_id = d2.id
from #deps d
join (
    select distinct child=t1.Item, parent=t2.item 
    from #tmp t1 
    join #tmp t2 on t1.path = t2.path and t1.ItemNumber-1 = t2.ItemNumber
    ) adj
on d.Department = adj.child
join #deps d2 on adj.parent = d2.Department;

检查

select * from #deps;
select * from #emps;

编辑

如果部门不是唯一的,请保持其路径,直到建立联系。这里DelimitedSplit8KWithPath 0是前面的DelimitedSplit8K返回父路径,只添加了一行,所以最终的SELECT是

 SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
        Item       = SUBSTRING(@pString, l.N1, l.L1),
        Parent     = LEFT(@pString, CASE WHEN l.N1>1 THEN l.N1-2 ELSE 0 END)
   FROM cteLen l

工作流程基本相同,查询更短

- 所有部门,包括目前没有员工的部门 select distinct Department = CASE WHEN len(parent)&gt; 0那么父母+'/'ELSE''结束+项目       ,d.parent       ,项目 进入#tmp 来自#sample_data 交叉应用dbo.DelimitedSplit8KWithPath(Department,'/')d;

- 部门

选择部门,     id = row_number()over(按部门排序),     PARENT_ID = NULL 进入#deps 来自#tmp

- 具有部门ID的员工

选择员工,    id = row_number()over(按Employee排序),    dep_id = d.id 进入#emps 来自#sample_data sd 在sd.department = d.Department加入#deps d;

- 现在是adjency

更新d 设置parent_id = d2.id  ,department = item 来自#deps d 在d.Department = adj.Department上加入#tmp adj 在adj.parent = d2.Department;

上加入#deps d2

从#deps中选择*; 从#emps;

中选择*