私は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ノードとその子ノードを削除したいとします。つまり、次のノードも削除されます: Costing、Cost Type、Cost Element、Reset 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
);
WITH 句の中に引数 ( WHERE ad_tree_id=1001 AND node_id=101) を入れていることがわかります。引数ステートメントを 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