0

SQL Antipatterns に記載されているレシピに基づいて、現在 MySQL を使用して隣接リストを使用しているシステムに推移閉包テーブルを改造しようとしています。ただし、サブツリーの移動の実装で問題が発生しました。

開発作業のために、既存のシステムとクロージャ テーブルを極端に単純化したものを作成しました。満足のいく方法で動作するようになったら、これを実際のデータに移植します。私のテーブルは次のとおりです。

CREATE TABLE `product` ( 
    `id` BigInt( 255 ) AUTO_INCREMENT NOT NULL, 
    `parent` BigInt( 255 ) NOT NULL, 
    `description` VarChar( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
     PRIMARY KEY ( `id` )
 )
CHARACTER SET = utf8
COLLATE = utf8_general_ci
ENGINE = InnoDB

CREATE TABLE `closure` ( 
    `ancestor` BigInt( 255 ) NOT NULL, 
    `decendant` BigInt( 255 ) NOT NULL, 
    `depth` BigInt( 255 ) NOT NULL,
     PRIMARY KEY ( `ancestor`,`decendant` )
 )
CHARACTER SET = utf8
COLLATE = utf8_general_ci
ENGINE = InnoDB;
CREATE INDEX `ancestordepth` USING BTREE ON `closure`( `ancestor`, `depth` )

私のテストデータは次のとおりです。

Product
=======
1,0,"Test 1"
2,0,"Test 2"
3,0,"Test 3"
4,1,"Test 4"
5,1,"Test 5"
6,1,"Test 6"
7,4,"Test 7"
8,4,"Test 8"
9,4,"Test 9"
10,7,"Test 10"

Closure
=======
1,1,0
1,4,1
1,5,1
1,6,1
1,7,2
1,8,2
1,9,2
1,10,3
2,2,0
3,3,0
4,4,0
4,7,1
4,8,1
4,9,1
4,10,2
5,5,0
6,6,0
7,7,0
7,10,1
8,8,0
9,9,0
10,10,0

製品テーブルの行作成時に閉鎖テーブルに行を挿入し、製品行が削除されたときに閉鎖テーブルから行を削除するトリガーを実装しましたが、それらは正常に動作しますが、MySQL の制限により、更新のケースを取得できません (製品テーブルの親が変更されます) が機能します。

ノード 1 ではなくノード 2 の子になるようにノード 4 を更新したい場合。

SQL アンチパターンの本では、これを行うためのクエリが提供されています。最初のものは、関連する行をクロージャ テーブルから削除することによって、既存のサブツリーを孤立させることを目的としています。

DELETE
FROM closure
WHERE decendant IN (
    SELECT decendant
    FROM closure
    WHERE ancestor = 4
)
AND ancestor IN (
    SELECT ancestor
    FROM closure
    WHERE decendant = 4
    AND ancestor != decendant
)

しかしもちろん、MySQL では、サブクエリで使用しているテーブルを変更できない設計上の欠陥があるため、これを行うことはできません。

そこから行を削除できるため、クエリを自己結合に書き直そうとしています。元のクエリを削除ではなく選択するように変更しました。これは機能するためです。比較のベースラインとして使用できます。ただし、結合を使用してクエリを複製しようとすると、空のセットが返されます。

SELECT *
FROM closure AS a
JOIN closure AS b ON a.ancestor = b.ancestor AND a.decendant = b.decendant
JOIN closure AS c ON a.ancestor = c.ancestor AND a.decendant = c.decendant
WHERE b.ancestor = 4
AND c.decendant = 4
AND c.ancestor != c.decendant

トリガーに入れる必要があるため、実行されるクエリを比較的単純に保つ必要があります。また、ライブ SQL サーバーがクラスターで実行されているため、一時テーブルも使用できません。一時テーブルを使用するとレプリケーションが壊れるという問題が過去にありました。MySQL で行を削除できるように、クエリをフォームに書き直すのを手伝ってくれる人がいれば、ありがたいです。

4

1 に答える 1

0

以下は、MySQLでそれを行う正しい方法のようです

    DELETE a
    FROM closure AS a
    JOIN closure AS b ON a.decendant = b.decendant
    LEFT JOIN closure AS c ON b.ancestor = c.ancestor and a.ancestor = c.decendant
    WHERE b.ancestor = OLD.id
    AND c.ancestor IS NULL; 
于 2015-03-19T15:49:36.987 に答える