2012-11-20 55 views
2

我有一個從父 - 子表(自連接,相鄰列表)產生扁平層次結構的查詢。問題是這個查詢爲沒有任何子級的級別生成NULL。現在我的意圖是'回填'這些級別,以生成一個不含任何級別列中的NULL值的表。我應該如何修改這個查詢?使用CTE的相鄰列表和遞歸查詢,如何回填?

實施例的數據:

SET NOCOUNT ON; 
USE Tempdb; 

IF OBJECT_ID('dbo.Employees', 'U') IS NOT NULL DROP TABLE dbo.Employees; 

CREATE TABLE dbo.Employees 
(
    empid INT   NOT NULL PRIMARY KEY, 
    mgrid INT   NULL  REFERENCES dbo.Employees, 
    empname VARCHAR(25) NOT NULL, 
    salary MONEY  NOT NULL, 
    CHECK (empid <> mgrid), 
    CHECK (empid > 0) 
); 

CREATE UNIQUE INDEX idx_unc_mgrid_empid ON dbo.Employees(mgrid, empid); 

INSERT INTO dbo.Employees(empid, mgrid, empname, salary) VALUES 
    (1, NULL, 'David' , $10000.00), 
    (2, 1, 'Eitan' , $7000.00), 
    (3, 1, 'Ina' , $7500.00), 
    (4, 2, 'Seraph' , $5000.00), 
    (5, 2, 'Jiru' , $5500.00), 
    (6, 2, 'Steve' , $4500.00), 
    (7, 3, 'Aaron' , $5000.00), 
    (8, 5, 'Lilach' , $3500.00), 
    (9, 7, 'Rita' , $3000.00), 
    (10, 5, 'Sean' , $3000.00), 
    (11, 7, 'Gabriel', $3000.00), 
    (12, 9, 'Emilia' , $2000.00), 
    (13, 9, 'Michael', $2000.00), 
    (14, 9, 'Didi' , $1500.00); 

查詢由@Andomar

; with Tree as 
     (
     SELECT empid 
     ,  mgrid 
     ,  1 as lv 
     ,  1 as level1 
     ,  null as level2 
     ,  null as level3 
     ,  null as level4 
     ,  null as level5 
     FROM Employees 
     WHERE mgrid IS NULL 
     UNION ALL 
     SELECT E.empid 
     ,  E.mgrid 
     ,  T.lv + 1 
     ,  T.level1 
     ,  case when T.lv = 1 then E.empid else t.level2 end 
     ,  case when T.lv = 2 then E.empid else t.level3 end 
     ,  case when T.lv = 3 then E.empid else t.level4 end 
     ,  case when T.lv = 4 then E.empid else t.level5 end 
     FROM Employees AS E 
     JOIN Tree T 
     ON  E.mgrid = T.empid 
     ) 
select * 
from Tree 
order by empid 

提供這產生

+-------+--------+----+--------+--------+--------+--------+--------+ 
| EMPID | MGRID | LV | LEVEL1 | LEVEL2 | LEVEL3 | LEVEL4 | LEVEL5 | 
+-------+--------+----+--------+--------+--------+--------+--------+ 
|  1 | (null) | 1 |  1 | (null) | (null) | (null) | (null) | 
|  2 | 1  | 2 |  1 | 2  | (null) | (null) | (null) | 
|  3 | 1  | 2 |  1 | 3  | (null) | (null) | (null) | 
|  4 | 2  | 3 |  1 | 2  | 4  | (null) | (null) | 
|  5 | 2  | 3 |  1 | 2  | 5  | (null) | (null) | 
|  6 | 2  | 3 |  1 | 2  | 6  | (null) | (null) | 
|  7 | 3  | 3 |  1 | 3  | 7  | (null) | (null) | 
|  8 | 5  | 4 |  1 | 2  | 5  | 8  | (null) | 
|  9 | 7  | 4 |  1 | 3  | 7  | 9  | (null) | 
| 10 | 5  | 4 |  1 | 2  | 5  | 10  | (null) | 
| 11 | 7  | 4 |  1 | 3  | 7  | 11  | (null) | 
| 12 | 9  | 5 |  1 | 3  | 7  | 9  | 12  | 
| 13 | 9  | 5 |  1 | 3  | 7  | 9  | 13  | 
| 14 | 9  | 5 |  1 | 3  | 7  | 9  | 14  | 
+-------+--------+----+--------+--------+--------+--------+--------+ 

但這個想法是實現這一

+-------+--------+----+--------+--------+--------+--------+--------+ 
| EMPID | MGRID | LV | LEVEL1 | LEVEL2 | LEVEL3 | LEVEL4 | LEVEL5 | 
+-------+--------+----+--------+--------+--------+--------+--------+ 
|  1 | (null) | 1 |  1 | 1  | 1  | 1  | 1  | 
|  2 | 1  | 2 |  1 | 2  | 2  | 2  | 2  | 
|  3 | 1  | 2 |  1 | 3  | 3  | 3  | 3  | 
|  4 | 2  | 3 |  1 | 2  | 4  | 4  | 4  | 
|  5 | 2  | 3 |  1 | 2  | 5  | 5  | 5  | 
|  6 | 2  | 3 |  1 | 2  | 6  | 6  | 6  | 
|  7 | 3  | 3 |  1 | 3  | 7  | 7  | 7  | 
|  8 | 5  | 4 |  1 | 2  | 5  | 8  | 8  | 
|  9 | 7  | 4 |  1 | 3  | 7  | 9  | 9  | 
| 10 | 5  | 4 |  1 | 2  | 5  | 10  | 10  | 
| 11 | 7  | 4 |  1 | 3  | 7  | 11  | 11  | 
| 12 | 9  | 5 |  1 | 3  | 7  | 9  | 12  | 
| 13 | 9  | 5 |  1 | 3  | 7  | 9  | 13  | 
| 14 | 9  | 5 |  1 | 3  | 7  | 9  | 14  | 
+-------+--------+----+--------+--------+--------+--------+--------+ 
+0

你是什麼意思? – jrara

回答

2

樹CTE

Select empid,mgrid,lv, 
     level1 = coalesce(level1,Rn), 
     level2 = coalesce(level2,Rn), 
     level3 = coalesce(level3,Rn), 
     level4 = coalesce(level4,Rn), 
     level5 = coalesce(level5,Rn) 
from 
(select empid,mgrid,lv,level1,level2,level3,level4,level5,Row_Number()Over(Order By empid) as Rn 
from Tree)x 

enter image description here

+0

非常巧妙的解決方案,在這種情況下工作! – jrara

2

只是簡單的嘗試修改結果的方式,你想在上次選擇中使用coalesce()

see sql-fiddle here

+0

從來不知道那裏有一個sql小提琴。太棒了。 – Mike

+0

其實這不是一個正確的結果集。 – jrara

+0

固定小提琴演示 – Nico

1

我發現也是這個工作後只需要添加以下:

; with Tree as 
     (
     SELECT empid 
     ,  mgrid 
     ,  1 as lv 
     ,  1 as level1 
     ,  null as level2 
     ,  null as level3 
     ,  null as level4 
     ,  null as level5 
     FROM Employees 
     WHERE mgrid IS NULL 
     UNION ALL 
     SELECT E.empid 
     ,  E.mgrid 
     ,  T.lv + 1 
     ,  T.level1 
     ,  case when T.lv = 1 then E.empid else t.level2 end 
     ,  case when T.lv = 2 then E.empid else t.level3 end 
     ,  case when T.lv = 3 then E.empid else t.level4 end 
     ,  case when T.lv = 4 then E.empid else t.level5 end 
     FROM Employees AS E 
     JOIN Tree T 
     ON  E.mgrid = T.empid 
     ) 
select empid, 
     mgrid, 
     lv, 
     level1, 
     level2 = coalesce(level2, level1), 
     level3 = coalesce(level3, level2, level1), 
     level4 = coalesce(level4, level3, level2, level1), 
     level5 = coalesce(level5, level4, level3, level2, level1) 
from Tree 
order by empid