我是存储过程的新手。作为我们的应用程序的一部分,我们有一个数据库,其中一个表具有子父关系。给定一个id,我们应该能够找出id的最终父节点,遍历表中的子父链接。
输入1:10943, 输出1:8656
输入2:5005, 输出2:9151,9160
不同的可能性
一个id可能有多个最终父母, id可能没有父级
任何输入都将受到赞赏。提前谢谢。
答案 0 :(得分:1)
树结构答案:
这完全取决于你的数据的流程,我的意思是,你的孩子和父母如何及时表现(插入,更新)以及表格有多大(数百,数千)
我们可以将这两种情况概括为:大表(数千+行)和小表(数百行)。在任何情况下,您都可以使用“结果”表来保存所有孩子的第一个父级。
小表
如果你的桌子不是一个大桌子,那么可以把所有的放在一个PL中。如果要实现“结果”表,请调用PL。
BIG TABLE
如果您的桌子很大(非常大),那么您必须使用触发器来更新“结果”表。而“结果”必须是Eager Materialized View。为了使它能够流畅地工作而不必每分钟等待几分钟。
这是一个关于如何在小桌子的情况下做到这一点的例子,如果它很大,它会是类似的,但你必须努力在触发器上使它工作正常。此示例仅以解释为目的显示DO格式的PL,您可以轻松更改PL:
-- YOUR EXAMPLE TABLE, without child with two parents
CREATE TEMP TABLE demo (child integer,parent integer);
INSERT INTO demo VALUES
(10943,6766),
(6766,9003),
(9003,8656),
(5005,6995),
(6995,9151),
(6996,9160);
-- DO, for inline PL
DO $$
DECLARE
-- Variables, note that for variable asignation its better if you use ':='
fathers integer[] := NULL;
father integer := 0;
firstfather integer := 0;
no_father boolean := 'f';
sons integer[] := NULL;
son integer := 0;
row integer := 1;
rows_length integer := 0;
BEGIN
-- Create "result" table for the example, the drop is in case you test many times the code
DROP TABLE IF EXISTS result;
CREATE TEMP TABLE result (sons integer,fathers integer);
SELECT array(SELECT child FROM demo)
INTO sons;
rows_length := array_length(sons,1);
-- Code that gets the first father of a child
LOOP
RAISE NOTICE 'son: %',sons[row];
son = sons[row];
LOOP
father := (SELECT parent FROM demo WHERE child=son);
IF father IS NULL
THEN
no_father='f';
ELSE
no_father='t';
fathers[row] := father;
son = father;
END IF;
EXIT WHEN no_father='f';
END LOOP;
RAISE NOTICE 'father: %',fathers[row];
-- INSERT in "result" son with its first father
INSERT into result(sons,fathers) values(sons[row],fathers[row]);
row := row+1;
EXIT WHEN rows_length < row;
END LOOP;
END $$;
-- Display "result"
SELECT * FROM result;
此代码生成下一个表:
Sons Fathers
---------------
10943 8656
6766 8656
9003 8656
5005 9151
6995 9151
6996 9160
注意:您的表显示了一个有两个父亲的孩子(6995),这在树状结构中是不可能的,这个例子适用于每个孩子都有一个父母的树结构。
答案 1 :(得分:1)
使用公用表表达式(CTE)可以更容易地将其编写为查询而不是作为过程。
假设我们有这张表al_test
:
+-----------+----------+
| parent_id | child_id |
+-----------+----------+
| 10943 | 6766 |
+-----------+----------+
| 6766 | 9003 |
+-----------+----------+
| 9003 | 8656 |
+-----------+----------+
| 5005 | 6995 |
+-----------+----------+
| 6995 | 9151 |
+-----------+----------+
| 6995 | 9160 |
+-----------+----------+
例如(PostgreSQL 8.4+),获取节点5005的所有父节点:
WITH RECURSIVE al_tree AS (
SELECT parent_id, child_id, 1 as depth
FROM al_test WHERE child_id = 5005
UNION ALL
SELECT al_test.parent_id, al_test.child_id, al_tree.depth + 1
FROM al_test, al_tree
WHERE al_test.child_id = al_tree.parent_id
)
SELECT parent_id
FROM al_tree
WHERE depth = (SELECT MAX(depth) FROM al_tree);
结果:
+-----------+
| parent_id |
+-----------+
| 9151 |
+-----------+
| 9160 |
+-----------+