基于分层数据的SQL更新

时间:2018-06-14 14:44:16

标签: sql sql-server tsql

对于基于经理的每位员工,应该取消部门。

如果经理的部门是null,那么它应该取回经理的部门。这个层次结构循环应该继续,直到它拿起一些部门。请查看附件中的数据或以下内容。

EmpName EmpId   MgrName MgrId   Dept
A         1        D      4 
B         2        D      4 
C         3        D      4 
D         4        E      5 
E         5        F      6 
F         6        G      7 
G         7        Q     17     CSC
H         8        I      9 
I         9        Q     17     MECH
J        10        O     15 
K        11        O     15 
L        12        O     15 
M        13        O     15 
N        14        O     15 
O        15        Q     17      EEE
P        16        Q     17 
Q        17                       IT

enter image description here

3 个答案:

答案 0 :(得分:0)

您可以将其余数据添加到此处并尝试一下:

DECLARE @table AS TABLE (EmpName NVARCHAR(1)
                        ,EmpId INT
                        ,MGRName NVARCHAR(1)
                        ,MgrID INT
                        ,Dept NVARCHAR(4)
                        )

INSERT  INTO @table
        (EmpName, EmpId, MGRName, MgrID, Dept)
VALUES  ('A', 1, 'D', 4, '')
,       ('B', 2, 'D', 4, '')
,       ('C', 3, 'D', 4, '')
,       ('D', 4, 'E', 5, '')
,       ('E', 5, 'F', 6, '')
,       ('F', 6, 'G', 7, '')
,       ('G', 7, 'Q', 17, 'CSC')
,       ('Q', 2, '', NULL, 'IT');
WITH    cte
          AS (SELECT    EmpName
              ,         EmpId
              ,         MGRName
              ,         MgrID
              ,         Dept
              FROM      @table t
              UNION ALL
              SELECT    c.EmpName
              ,         c.EmpId
              ,         t2.MGRName
              ,         t2.MgrID
              ,         t2.Dept
              FROM      @table t2
              JOIN      cte C ON c.MGRId = t2.EmpId
                AND c.Dept = ''
             )
    SELECT  *
    FROM    cte
    WHERE Dept <> ''
    ORDER BY EMpName

对于将来的问题,如果您提供表格声明和样本数据作为我们可以剪切和粘贴的内容,您可能会得到更多回复。

答案 1 :(得分:0)

您可以直接从递归查询更新。

;with RCTE as
(
    select EmpId as RootEmpId, 0 as Lvl, EmpId, MgrID, Dept
    from Employee
    where Dept is null

    union all

    select r.RootEmpId, r.Lvl + 1, e.EmpId, e.MgrID, e.Dept
    from RCTE r
    join Employee e on e.EmpId = r.MgrID
    where r.Dept is null
) 
update e
set Dept = r.Dept
from Employee e 
join RCTE r on (e.EmpId = r.RootEmpId and r.Dept is not null)
where e.Dept is null;

示例测试代码段

declare @Employee table (EmpId int primary key, EmpName nvarchar(100), MgrID int, Dept NVARCHAR(4));

insert into @Employee (EmpName, EmpId, MgrID, Dept) VALUES  
 ('A',1,4,null)
,('B',2,4,null)
,('C',3,4,null)
,('D',4,5,null)
,('E',5,6,null)
,('F',6,7,null)
,('G',7,17,'CSC')
,('H',8,9,null)
,('I',9,17,'MECH')
,('J',10,15,null)
,('K',11,15,null)
,('L',12,15,null)
,('M',13,15,null)
,('N',14,15,null)
,('O',15,17,'EEE')
,('P',16,17,null)
,('Q',17,null,'IT')
;

;with RCTE as
(
    select EmpId as RootEmpId, 0 as Lvl, EmpId, MgrID, Dept
    from @Employee
    where Dept is null

    union all

    select r.RootEmpId, r.Lvl + 1, e.EmpId, e.MgrID, e.Dept
    from RCTE r
    join @Employee e on e.EmpId = r.MgrID
    where r.Dept is null
) 
update e
set Dept = r.Dept
from @Employee e 
join RCTE r on (e.EmpId = r.RootEmpId and r.Dept is not null)
where e.Dept is null;

select 
 e.EmpName, e.EmpId, e.MgrID, e.Dept, 
 m.EmpName as MgrName, m.Dept as MgrDept
from @Employee e
join @Employee m on (m.EmpId = e.MgrID)
order by EmpId;

旁注:本着normalization的精神,维持一个部门表会更常见。然后只需将DepartmentID外键存储在Customer表中。而不是可以改变的部门名称。

答案 2 :(得分:0)

我认为这样做会 您通过包含mgr名称

来对数据进行非格式化
declare @t table (Emp char, Id int, MgrId int, Dept varchar(10))
insert @t values
('A',  1,    4,  null),
('B',  2,    4,  null), 
('C',  3,    4,  null), 
('D',  4,    5,  null), 
('E',  5,    6,  null), 
('F',  6,    7,  null), 
('G',  7,   17, 'CSC'),
('H',  8,    9,  null), 
('I',  9,   17, 'MCH'),
('J', 10,   15,  null), 
('K', 11,   15,  null), 
('L', 12,   15,  null), 
('M', 13,   15,  null), 
('N', 14,   15,  null), 
('O', 15,   17, 'EEE'),
('P', 16,   17,  null), 
('Q', 17, null, 'IT');
with cte as 
( select t1.Id, t1.emp, t1.MgrId, isnull(t1.Dept, t2.Dept) as Dept, t2.Emp as 'mgr', t2.MgrId as nextMgr 
    from @t t1
    left join @t t2 
      on t2.Id = t1.MgrId
    --where not exists ( select * from @t t where t.MgrId = t1.Id )
    union all 
    select t1.Id, t1.emp, t1.MgrId, t2.Dept, t1.mgr, t2.MgrId as nextMgr
    from cte t1  
    join @t t2 
      on t2.Id = t1.nextMgr
     and t1.Dept is null
)
select * 
from cte 
where Dept is not null
order by id

Id          emp  MgrId       Dept       mgr  nextMgr
----------- ---- ----------- ---------- ---- -----------
1           A    4           CSC        D    17
2           B    4           CSC        D    17
3           C    4           CSC        D    17
4           D    5           CSC        E    17
5           E    6           CSC        F    17
6           F    7           CSC        G    17
7           G    17          CSC        Q    NULL
8           H    9           MCH        I    17
9           I    17          MCH        Q    NULL
10          J    15          EEE        O    17
11          K    15          EEE        O    17
12          L    15          EEE        O    17
13          M    15          EEE        O    17
14          N    15          EEE        O    17
15          O    17          EEE        Q    NULL
16          P    17          IT         Q    NULL
17          Q    NULL        IT         NULL NULL