如何从表中删除树节点及其子记录(没有级联删除)?
作者:互联网
我在postgreSQL v9.1中有这个表:
CREATE TABLE ad_treenodemm
(
ad_tree_id numeric(10,0) NOT NULL,
node_id numeric(10,0) NOT NULL,
ad_client_id numeric(10,0) NOT NULL,
ad_org_id numeric(10,0) NOT NULL,
name character varying(60) NOT NULL,
isactive character(1) NOT NULL DEFAULT 'Y'::bpchar,
created timestamp without time zone NOT NULL DEFAULT now(),
createdby numeric(10,0) NOT NULL,
updated timestamp without time zone NOT NULL DEFAULT now(),
updatedby numeric(10,0) NOT NULL,
parent_id numeric(10,0),
seqno numeric(10,0),
CONSTRAINT ad_treenodemm_pkey PRIMARY KEY (ad_tree_id , node_id ),
CONSTRAINT adtree_adtreenodemm FOREIGN KEY (ad_tree_id)
REFERENCES adempiere.ad_tree (ad_tree_id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
CONSTRAINT ad_treenodemm_isactive_check CHECK (isactive = ANY (ARRAY['Y'::bpchar, 'N'::bpchar]))
)
重要栏目说明:
* ad_tree_id =树组ID(连接到ad_tree表)
* node_id =节点ID
* parent_id =父节点id(如果0 =>表示节点在顶部)
列的休止符可以忽略.
例如,我有这样的ad_treenodemm表数据表示:
# Group1 (all node belows are assigned with ad_tree_id=1001)
-Accounting (node_id=101, parent_id=0)
-Costing (node_id=202, parent_id=101)
-Cost Type (node_id=103, parent_id=202)
-Cost Element (node_id=24, parent_id=202)
-Client Accounting Processor (node_id=105, parent_id=101)
-Reset Accounting (node_id=6, parent_id=101)
...
-Finance (node_id=4110, parent_id=0)
...
# Group2 (all node belows are assigned with ad_tree_id=1002)
...
假设我想删除Group1中的Accounting节点及其子节点.这意味着,它还会删除节点:成本核算,成本类型,成本要素,重置会计等等.怎么做?
解决方案可以是带有JDBC的SQL或Java语言(但如果可能,SQL将是首选).
更新:
我找到了一个WITH RECURSIVE(CTE)sql的解决方案,但它并不太优雅:
WITH RECURSIVE temp(ad_tree_id, node_id, parent_id) AS (
SELECT a.ad_tree_id, a.node_id, a.parent_id
FROM ad_treenodemm a
WHERE ad_tree_id=1001 AND node_id=101 -- look at this
UNION ALL
SELECT b.ad_tree_id, b.node_id, b.parent_id
FROM ad_treenodemm b
INNER JOIN temp c on c.node_id = b.parent_id
WHERE b.ad_tree_id=c.ad_tree_id
)
DELETE FROM ad_treenodemm a
WHERE (a.ad_tree_id, a.node_id) IN (
SELECT ad_tree_id, node_id FROM temp
);
您看到我将参数(WHERE ad_tree_id = 1001 AND node_id = 101)放在WITH子句中.有人知道如何通过将参数语句放在WITH子句之外来改进SQL吗?
对于想要在不删除记录的情况下试验查询的任何人,请使用以下命令:
WITH RECURSIVE temp(ad_tree_id, node_id, parent_id) AS (
SELECT a.ad_tree_id, a.node_id, a.parent_id
FROM ad_treenodemm a
WHERE ad_tree_id=1001 AND node_id=101
UNION ALL
SELECT b.ad_tree_id, b.node_id, b.parent_id
FROM ad_treenodemm b
INNER JOIN temp c on c.node_id = b.parent_id
WHERE b.ad_tree_id=c.ad_tree_id
)
SELECT * FROM ad_treenodemm a
WHERE (a.ad_tree_id, a.node_id) IN (
SELECT ad_tree_id, node_id FROM temp
)
ORDER BY a.parent_id, a.node_id
解决方法:
由于您不想“改变表结构”,因此无论如何都要降至recursive query(或递归执行工作的函数).因为添加FK约束将符合“改变表结构”的条件.
如果没有这些限制,最优雅的解决方案是修复您提到的NULL值并将NOT NULL constraint添加到列中.然后按照注释中的说明添加带有ON DELETE CASCADE的FK constraint,首先是@lc.
递归查询
具有可写CTE的DELETE可能如下所示:
WITH RECURSIVE x AS (
SELECT ad_tree_id, node_id
FROM ad_treenodemm
WHERE (ad_tree_id, node_id) = (1,5) -- enter dead node walking here
UNION ALL
SELECT a.ad_tree_id, a.node_id
FROM x
JOIN ad_treenodemm a ON a.parent_id = x.node_id
)
DELETE FROM ad_treenodemm a
USING x
WHERE (a.ad_tree_id, a.node_id) = (x.ad_tree_id, x.node_id)
要在一个步骤中执行此操作,您需要在data-modifying CTEs中使用PostgreSQL 9.1或更高版本.否则,您必须运行单独的SELECT来收集行,然后再执行DELETE.
标签:java,sql,postgresql,sql-delete,tree 来源: https://codeday.me/bug/20190901/1785139.html