如何从自引用表中确定每个人的结构

Mat*_*lko 7 sql hierarchy self-join pervasive-sql

我有以下表格:

Employees
-------------
ClockNo     int
CostCentre  varchar
Department  int
Run Code Online (Sandbox Code Playgroud)

Departments
-------------
DepartmentCode  int
CostCentreCode  varchar
Parent          int
Run Code Online (Sandbox Code Playgroud)

部门可以将其他部门作为父母,这意味着存在无限的等级.所有部门都属于成本中心,因此总是有一个CostCentreCode.如果parent = 0是顶级部门

员工必须具有CostCentre价值,但可能具有Department0,这意味着他们不在某个部门

我想要尝试生成的是一个查询,它将提供最多四层次的层次结构.像这样:

EmployeesLevels
-----------------
ClockNo
CostCentre
DeptLevel1
DeptLevel2
DeptLevel3
DeptLevel4
Run Code Online (Sandbox Code Playgroud)

我已经设法得到一些东西来显示它自己的部门结构,但我无法弄清楚如何在不创建重复的员工行的情况下将其链接到员工:

SELECT d1.Description AS lev1, d2.Description as lev2, d3.Description as lev3, d4.Description as lev4
FROM departments AS d1
LEFT JOIN departments AS d2 ON d2.parent = d1.departmentcode
LEFT JOIN departments AS d3 ON d3.parent = d2.departmentcode
LEFT JOIN departments AS d4 ON d4.parent = d3.departmentcode
WHERE d1.parent=0;
Run Code Online (Sandbox Code Playgroud)

SQL要创建Structure和一些示例数据:

CREATE TABLE Employees(
ClockNo integer NOT NULL PRIMARY KEY,
CostCentre varchar(20) NOT NULL,
Department integer NOT NULL);

CREATE TABLE Departments(
DepartmentCode integer NOT NULL PRIMARY KEY,
CostCentreCode varchar(20) NOT NULL,
Parent integer NOT NULL
);

CREATE INDEX idx0 ON Employees (ClockNo);
CREATE INDEX idx1 ON Employees (CostCentre, ClockNo);
CREATE INDEX idx2 ON Employees (CostCentre);

CREATE INDEX idx0 ON Departments (DepartmentCode);
CREATE INDEX idx1 ON Departments (CostCentreCode, DepartmentCode);

INSERT INTO Employees VALUES (1, 'AAA', 0);
INSERT INTO Employees VALUES (2, 'AAA', 3);
INSERT INTO Employees VALUES (3, 'BBB', 0);
INSERT INTO Employees VALUES (4, 'BBB', 4);
INSERT INTO Employees VALUES (5, 'CCC', 0); 
INSERT INTO Employees VALUES (6, 'AAA', 1);
INSERT INTO Employees VALUES (7, 'AAA', 5);
INSERT INTO Employees VALUES (8, 'AAA', 15);

INSERT INTO Departments VALUES (1, 'AAA', 0);
INSERT INTO Departments VALUES (2, 'AAA', 1);
INSERT INTO Departments VALUES (3, 'AAA', 1);
INSERT INTO Departments VALUES (4, 'BBB', 0);
INSERT INTO Departments VALUES (5, 'AAA', 3);
INSERT INTO Departments VALUES (12, 'AAA', 5);
INSERT INTO Departments VALUES (15, 'AAA', 12);
Run Code Online (Sandbox Code Playgroud)

这给出了以下结构(员工时钟数字在方括号中):

Root
  |
  |---AAA                   [1]
  |    \---1                [6]
  |       |---2     
  |       \---3             [2]
  |          \---5          [7]
  |             \---12
  |                \---15   [8]
  |
  |---BBB                   [3]
  |    \---4                [4]
  |
  \---CCC                   [5]
Run Code Online (Sandbox Code Playgroud)

该查询应返回以下内容:

ClockNo CostCentre Level1 Level2 Level3 Level4
1       AAA        
2       AAA        1      3
3       BBB
4       BBB        4
5       CCC
6       AAA        1
7       AAA        1      3       5
8       AAA        1      3       5      12  *
Run Code Online (Sandbox Code Playgroud)

*在员工8的情况下,他们在5级.理想情况下,我希望将所有级别显示为level4,但我很高兴在这种情况下显示CostCentre

Ser*_*erg 1

SunnyMagadan 的询问很好。但是,根据部门中的员工数量,您可能希望尝试以下方法,这使数据库优化器有机会为一个部门仅遍历一次部门层次结构,而不是为部门中的每个员工重复一次。

SELECT e.ClockNo, e.CostCentre,  Level1, Level2, Level3, Level4
FROM Employees e
LEFT JOIN 
    (SELECT 
         d1.departmentcode
        , d1.CostCentreCode
        , coalesce (d4.departmentcode, d3.departmentcode
                    , d2.departmentcode, d1.departmentcode) AS Level1
        , case when d4.departmentcode is not null then d3.departmentcode        
               when d3.departmentcode is not null then d2.departmentcode
               when d2.departmentcode is not null then d1.departmentcode end as Level2
        , case when d4.departmentcode is not null then d2.departmentcode
               when d3.departmentcode is not null then d1.departmentcode end as Level3
        , case when d4.departmentcode is not null then d1.departmentcode end as Level4
    FROM departments AS d1
    LEFT JOIN departments AS d2 ON d1.parent = d2.departmentcode
    LEFT JOIN departments AS d3 ON d2.parent = d3.departmentcode
    LEFT JOIN departments AS d4 ON d3.parent = d4.departmentcode) d
ON d.DepartmentCode = e.Department AND d.CostCentreCode = e.CostCentre
;
Run Code Online (Sandbox Code Playgroud)

编辑关于 5 级以上部门。

任何固定步骤查询都无法获取它们的前 4 个级别。因此,更改上面的查询只是为了以某种方式标记它们,例如 -1。

, case when d4.Parent > 0 then NULL else 
    coalesce (d4.departmentcode, d3.departmentcode
            , d2.departmentcode, d1.departmentcode) end AS Level1
Run Code Online (Sandbox Code Playgroud)

等等。