让我们假设我有一个自引用分层表构建像这样的经典方式:
CREATE TABLE test (name text,id serial primary key,parent_id integer references test); insert into test (name,id,parent_id) values ('root1',1,NULL),('root2',2,NULL),('root1sub1',3,1),('root1sub2',4,1),('root 2sub1',5,2),('root2sub2',6,2); testdb=# select * from test; name | id | parent_id -----------+----+----------- root1 | 1 | root2 | 2 | root1sub1 | 3 | 1 root1sub2 | 4 | 1 root2sub1 | 5 | 2 root2sub2 | 6 | 2
我现在需要的是一个函数(最好是在普通的sql中),它将获取测试记录的id并克隆所有附加的记录(包括给定的记录).克隆的记录当然需要有新的ID.期望的结果将是这样的例如:
Select * from cloningfunction(2); name | id | parent_id -----------+----+----------- root2 | 7 | root2sub1 | 8 | 7 root2sub2 | 9 | 7
有什么指针吗?我正在使用PostgreSQL 8.3.
递归地拉这个结果是棘手的(虽然可能).然而,这通常不是很有效,且有很多更好的方法来解决这个问题.
基本上,你用一个额外的列来扩充表格,该列将树跟踪到顶部 - 我将其称为"Upchain".它只是一个长字符串,看起来像这样:
name | id | parent_id | upchain root1 | 1 | NULL | 1: root2 | 2 | NULL | 2: root1sub1 | 3 | 1 | 1:3: root1sub2 | 4 | 1 | 1:4: root2sub1 | 5 | 2 | 2:5: root2sub2 | 6 | 2 | 2:6: root1sub1sub1 | 7 | 3 | 1:3:7:
通过使用表格上的触发器来更新此字段非常容易.(对于术语表示道歉,但我总是使用SQL Server完成此操作).每次添加或删除记录或更新parent_id字段时,只需更新树的该部分上的upchain字段.这是一项微不足道的工作,因为你只需要获取父记录的upchain并附加当前记录的id.使用LIKE可以轻松识别所有子记录,以检查其upchain中包含起始字符串的记录.
当你来阅读数据时,你正在有效地做的是交换一些额外的写入活动来节省大笔费用.
当你想在树中选择一个完整的分支时,它是微不足道的.假设您想要节点1下的分支.节点1有一个上行链路'1:',因此您知道该节点下树的分支中的任何节点必须具有从'1:...'开始的上行链路.所以你这样做:
SELECT * FROM table WHERE upchain LIKE '1:%'
这非常快(当然是索引上链字段).作为奖励,它还使许多活动变得非常简单,例如找到部分树,树内等级等.
我已经在跟踪大型员工报告层次结构的应用程序中使用了它,但您可以将它用于几乎任何树结构(部件细分等)
备注(对任何感兴趣的人):
我没有给出SQL代码的一步一步,但是一旦你得到了原理,它实现起来非常简单.我不是一个优秀的程序员,所以我从经验中说话.
如果表中已有数据,则需要进行一次更新以使upchains最初同步.同样,这并不困难,因为代码与触发器中的UPDATE代码非常相似.
这种技术也是识别循环引用的好方法,否则这些引用可能很难发现.