SQL 将所有 parents 的外键值组合成 child

SQL combine foreign key values of all parents into child

在一个 informix 数据库中,我有一个分层树结构,其中一个 child 条目可以有任何级别的 parents (parent, grandparent, ETC)。通过与其 parent 条目的关系。

每个条目都有一个属性名称和值的集合。

表格建模如下:

node:

+-------------+----------------------+--------+
|     id      |       parn_id        |  name  |
+-------------+----------------------+--------+
| int         | int                  | string |
| primary key | existing id, or null |        |
+-------------+----------------------+--------+

vals:


+-----------------------+-------------+---------+
|          id           |   atr_id    | atr_val |
+-----------------------+-------------+---------+
| int                   | int         | string  |
| foreign key from node | primary key |         |
+-----------------------+-------------+---------+

look:

+-----------------------+--------+
|        atr_id         |  name  |
+-----------------------+--------+
| int                   | string |
| foreign key from vals |        |
+-----------------------+--------+

我需要一个 sql 查询,其中 return 在请求 child 时所有 parent 的(vals,look)对。

例如,如果我有

Parent: (valP, nameP), (valP2, nameP2)
*
* * * Child (valC, nameC)
      *
      * * * GrandChild (valGC, nameGC)

然后我查询 GrandChild,我希望它 return:

GrandChild (valP, nameP), (valP2, nameP2), (valC, nameC), (valGC, nameGC)

使用最新的 Informix 版本(我使用的是 Informix 14.10.FC1),您可以使用 CONNECT BY 子句来处理分层查询。

设置,根据您的描述:

CREATE TABLE node
(
    id      INTEGER PRIMARY KEY,
    parn_id INTEGER,
    name    CHAR( 20 ) NOT NULL
);
INSERT INTO node VALUES ( 1, NULL, 'Node_A' );
INSERT INTO node VALUES ( 2, NULL, 'Node_B' );
INSERT INTO node VALUES ( 3, NULL, 'Node_C' );
INSERT INTO node VALUES ( 4, 2, 'Node_D' );
INSERT INTO node VALUES ( 5, 3, 'Node_E' );
INSERT INTO node VALUES ( 6, 3, 'Node_F' );
INSERT INTO node VALUES ( 7, 4, 'Node_G' );

CREATE TABLE vals
(
    id      INTEGER NOT NULL REFERENCES node( id ),
    atr_id  INTEGER PRIMARY KEY,
    atr_val CHAR( 20 ) NOT NULL    
);
INSERT INTO vals VALUES ( 1,  1, 'Value_A_1' );
INSERT INTO vals VALUES ( 2,  2, 'Value_B_1' );
INSERT INTO vals VALUES ( 2,  3, 'Value_B_2' );
INSERT INTO vals VALUES ( 3,  4, 'Value_C_1' );
INSERT INTO vals VALUES ( 3,  5, 'Value_C_2' );
INSERT INTO vals VALUES ( 4,  6, 'Value_D_1' );
INSERT INTO vals VALUES ( 5,  7, 'Value_E_1' );
INSERT INTO vals VALUES ( 5,  8, 'Value_E_2' );
INSERT INTO vals VALUES ( 6,  9, 'Value_F_1' );
INSERT INTO vals VALUES ( 7, 10, 'Value_G_1' );

CREATE TABLE look
(
    atr_id  INTEGER NOT NULL REFERENCES vals( atr_id ),
    name    CHAR( 20 ) NOT NULL
);
INSERT INTO look VALUES (  1, 'Look_A_1' );
INSERT INTO look VALUES (  2, 'Look_B_1' );
INSERT INTO look VALUES (  3, 'Look_B_2' );
INSERT INTO look VALUES (  4, 'Look_C_1' );
INSERT INTO look VALUES (  5, 'Look_C_2' );
INSERT INTO look VALUES (  6, 'Look_D_1' );
INSERT INTO look VALUES (  7, 'Look_E_1' );
INSERT INTO look VALUES (  8, 'Look_E_2' );
INSERT INTO look VALUES (  9, 'Look_F_1' );
INSERT INTO look VALUES ( 10, 'Look_G_1' );

我们可以使用CONNECT BY来查找childparents,例如:

-- Starting from 'Node_G'
SELECT
    n.id,
    n.parn_id,
    n.name,
    CONNECT_BY_ROOT n.name AS starting_node
FROM
    node AS n
START WITH n.name = 'Node_G'
CONNECT BY PRIOR n.parn_id = n.id
ORDER BY
    n.name
;

-- RESULTS:
     id     parn_id name        starting_node

      2             Node_B      Node_G
      4           2 Node_D      Node_G
      7           4 Node_G      Node_G

然后我们可以加入属性表:

SELECT
    vt1.starting_node,
    v.atr_val,
    l.name
FROM
(
    SELECT
        n.id,
        n.parn_id,
        n.name,
        CONNECT_BY_ROOT n.name AS starting_node
    FROM
        node AS n
    START WITH n.name = 'Node_G'
    CONNECT BY PRIOR n.parn_id = n.id
) AS vt1
INNER JOIN vals AS v
ON
    v.id = vt1.id
INNER JOIN look AS l
ON
    l.atr_id = v.atr_id
ORDER BY
    vt1.starting_node, v.atr_val
;

-- RESULTS:
starting_node        atr_val              name

Node_G               Value_B_1            Look_B_1
Node_G               Value_B_2            Look_B_2
Node_G               Value_D_1            Look_D_1
Node_G               Value_G_1            Look_G_1

如果我们删除 START WITH 子句,我们将得到每个节点的分层结果:

SELECT
    vt1.starting_node,
    v.atr_val,
    l.name
FROM
(
    SELECT
        n.id,
        n.parn_id,
        n.name,
        CONNECT_BY_ROOT n.name AS starting_node
    FROM
        node AS n
    CONNECT BY PRIOR n.parn_id = n.id
) AS vt1
INNER JOIN vals AS v
ON
    v.id = vt1.id
INNER JOIN look AS l
ON
    l.atr_id = v.atr_id
ORDER BY
    vt1.starting_node, v.atr_val
;

-- RESULTS:
starting_node        atr_val              name

Node_A               Value_A_1            Look_A_1
Node_B               Value_B_1            Look_B_1
Node_B               Value_B_2            Look_B_2
Node_C               Value_C_1            Look_C_1
Node_C               Value_C_2            Look_C_2
Node_D               Value_B_1            Look_B_1
Node_D               Value_B_2            Look_B_2
Node_D               Value_D_1            Look_D_1
Node_E               Value_C_1            Look_C_1
Node_E               Value_C_2            Look_C_2
Node_E               Value_E_1            Look_E_1
Node_E               Value_E_2            Look_E_2
Node_F               Value_C_1            Look_C_1
Node_F               Value_C_2            Look_C_2
Node_F               Value_F_1            Look_F_1
Node_G               Value_B_1            Look_B_1
Node_G               Value_B_2            Look_B_2
Node_G               Value_D_1            Look_D_1
Node_G               Value_G_1            Look_G_1