使用 PostgresSQL 的递归 SQL 查询

Recursive SQL Queries with PostgreSQL

场景:

我有一个应用程序可以接收一个或多个输入并生成一个或多个输出。

应用程序可以使用一次或多次执行的输出作为新执行的输入。

在某些情况下,数据会失效,并且所有直接或间接使用该数据的执行生成的输出数据也必须失效。

这就是我尝试完成它的方式:

CREATE TABLE execution (
    execution_id INT,
    data VARCHAR(36),    
    direction CHAR(1) NOT NULL CHECK (direction = 'I' OR direction = 'O'),
    PRIMARY KEY (execution_id, data));

INSERT INTO execution VALUES (1, 'aaaa', 'O');
INSERT INTO execution VALUES (1, 'bbbb', 'O');

INSERT INTO execution VALUES (2, 'aaaa', 'I');
INSERT INTO execution VALUES (2, 'bbbb', 'I');
INSERT INTO execution VALUES (2, 'cccc', 'O');
INSERT INTO execution VALUES (2, 'dddd', 'O');

INSERT INTO execution VALUES (3, 'aaaa', 'I');
INSERT INTO execution VALUES (3, 'cccc', 'I');
INSERT INTO execution VALUES (3, 'eeee', 'O');

INSERT INTO execution VALUES (4, 'bbbb', 'I');
INSERT INTO execution VALUES (4, 'ffff', 'O');

对于此数据,当我请求将受到 'aaaa' 数据失效影响的执行链时,我希望得到:

原因:

查询:

WITH RECURSIVE execution_chain AS (
        SELECT execution_id, data, direction, 1 AS level
        FROM execution 
        WHERE data = 'aaaa' AND direction = 'O'
    UNION ALL
        SELECT e.execution_id, e.data, e.direction, e.level + 1
        FROM execution e
        WHERE e.execution_id IN (
            SELECT e.execution_id
            FROM execution e
            JOIN execution_chain 
            ON e.data = execution_chain.data
            WHERE e.execution_id > execution_chain.execution_id
        )
        AND e.direction = 'O'
)
SELECT * FROM execution_chain;

我收到这个错误:

ERROR:  recursive reference to query "execution_chain" must not appear within a subquery
LINE 11:     JOIN execution_chain ec
                  ^
SQL state: 42P19
Character: 339 

任何关于如何“修复”此查询的想法都将不胜感激。

为了简化查询,首先计算要遵循的执行依赖关系

WITH RECURSIVE dep as (
    select i.data, i.execution_id idin, o.execution_id idout 
    from execution i
    join execution o on i.data = o.data and i.direction = 'I' and o.direction = 'O'
),
execution_chain AS (
    SELECT execution_id, data, direction, 1 AS level
    FROM execution 
    WHERE data = 'aaaa' and direction = 'O'
    
    UNION ALL
    
    SELECT e.execution_id, e.data, e.direction, ec.level + 1
    FROM execution_chain ec 
    JOIN dep ON dep.data = ec.data AND dep.idout = ec.execution_id
    JOIN execution e ON e.execution_id = dep.idin AND e.direction ='O'
)
SELECT distinct execution_id, data, direction
FROM execution_chain
WHERE level > 1
ORDER BY execution_id, data;

db<>fiddle