1$pdo->beginTransaction();2$sql="UPDATE tbl SET level=0,l=0,r=0;\n";3$stmt=$pdo->query($sql);4$sql="UPDATE tbl SET level=1,l=(SELECT @a:=@a+1 FROM (SELECT @a:=0) AS sub),r=@a:=@a+1 WHERE parent_id IS NULL ORDER BY id;";5$stmt=$pdo->query($sql);6$sql="SELECT id FROM tbl WHERE level=0 ORDER BY parent_id ASC,id DESC;";7$stmt2=$pdo->query($sql);8while($row=$stmt2->fetch()){9$sql='UPDATE tbl as a1,tbl as a2,tbl as a3 SET a1.l=a2.l+1,a1.r=a2.l+2,a1.level=a2.level+1,a2.r=a2.r+2,a3.r=a3.r+2 WHERE a1.parent_id=a2.id AND a2.l<a3.r AND a1.id=?;';10$stmt=$pdo->prepare($sql);11$stmt->execute([$row["id"]]);12$sql='UPDATE tbl as a1,tbl as a2,tbl as a3 SET a3.l=a3.l+2 WHERE a1.parent_id=a2.id AND a2.l<a3.l and a3.id!=a1.id AND a1.id=?;';13$stmt=$pdo->prepare($sql);14$stmt->execute([$row["id"]]);15}1617$sql='SELECT name,level,(SELECT COUNT(*)-1 FROM tbl AS t2 WHERE t2.l BETWEEN t1.l AND t1.r) AS child FROM tbl AS t1 ORDER BY l;';18$stmt=$pdo->query($sql);19$rows=$stmt->fetchAll();20$pdo->commit();// 実はロールバックしてもOK $pdo->rollback();21
入れ子集合モデルのsample
隣接モデルを入れ子集合モデルに変換するために
以下のプロシージャを作っておきます。
SQL
1DROPPROCEDUREIFEXISTS SET_LR;2DELIMITER//3CREATEPROCEDURE SET_LR()4BEGIN5DECLARE a INTDEFAULT0;6DECLARE done INTDEFAULT0;7DECLARE CUR CURSORFOR8SELECT id FROM tbl WHERElevel=0ORDERBY parent_id ASC,sort DESC,id DESC;9DECLARECONTINUEHANDLERFOR SQLSTATE '02000'SET done =1;10UPDATE tbl SETlevel=0,l=0,r=0;11/* level,l,rを初期化*/1213UPDATE tbl SETlevel=1,l=(SELECT@a:=@a+1FROM(SELECT@a:=0)AS sub),r=@a:=@a+114WHERE parent_id ISNULL15ORDERBY sort ASC,id ASC;16/* 先頭データのlevelを1とし、l,rを1ずつ足していく*/1718OPEN CUR;19REPEAT20FETCH CUR INTO a;21IFNOT done THEN22SET@id=a;23SET@sql='UPDATE tbl as a1,tbl as a2,tbl as a3 SET a1.l=a2.l+1,a1.r=a2.l+2,a1.level=a2.level+1,a2.r=a2.r+2,a3.r=a3.r+2 WHERE a1.parent_id=a2.id AND a2.l<a3.r AND a1.id=?';24/* 子のlに親の1+1、子のrに親のl+2,子のlevelに親のlevel+1親のrを2増やす、親のlより大きいrを2増やす */2526PREPARE stmt from@sql;27EXECUTE stmt USING@id;28SET@sql='UPDATE tbl as a1,tbl as a2,tbl as a3 SET a3.l=a3.l+2 WHERE a1.parent_id=a2.id AND a2.l<a3.l and a3.id!=a1.id AND a1.id=?';29/* 親の1より大きいlの内、子以外のものを2増やす */3031PREPARE stmt from@sql;32EXECUTE stmt USING@id;33ENDIF;34UNTIL done ENDREPEAT;35CLOSE CUR;36END37//38DELIMITER;39
>>phpMyAdminの場合は、黒くはないと思います
DBを選んだ状態で「SQL」タブを押すと
「クエリを実行する」という入力エリアが表示されるので
そこに貼り付けて「実行」してください
最近のphpMyAdminであれば、どんなプロシージャが登録されているか
可視化できる仕組みになっているはずです
反応が遅れてしまい大変申し訳ありません。。
SQL文で入力したのですが下記のエラーがでてしまして、
SQL query:
DELIMITER ;
MySQL のメッセージ: ドキュメント
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DELIMITER' at line 1
もしかしたらSQL部分に直接入力することではないのか?と思いまして。。
すみませんtypoです。
「r int not null);」が正しいので修正しました。
一応ただしく動いた場合のリストの状況を載せました。
MySQLの5.7ならストアド・プロシージャは利用できるので
問題ないはずなのですけどね・・・
ついでなので、子要素数のとり方も追記して最終形まで記載しておきました
なんとかプロシージャを動かせると良いのですが・・・
連絡が遅れましたが
もう一度phpadminのSQLで上記のものをたたきましたがやはり
SQL query:
DELIMITER ;
MySQL のメッセージ: ドキュメント
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DELIMITER' at line 1
とエラーが出てしまいます。
ただページを更新してみるとプロシージャといった項目が追加されていました!
BEGIN
DECLARE a INT DEFAULT 0;
DECLARE done INT DEFAULT 0;
DECLARE CUR CURSOR FOR
SELECT id FROM tbl WHERE level=0 ORDER BY parent_id ASC,sort DESC,id DESC;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
UPDATE tbl SET level=0,l=0,r=0;
/* level,l,rを初期化*/
UPDATE tbl SET level=1,l=(SELECT @a:=@a+1 FROM (SELECT @a:=0) AS sub),r=@a:=@a+1
WHERE parent_id IS NULL
ORDER BY sort ASC,id ASC;
/* 先頭データのlevelを1とし、l,rを1ずつ足していく*/
OPEN CUR;
REPEAT
FETCH CUR INTO a;
IF NOT done THEN
SET @id=a;
SET @sql='UPDATE tbl as a1,tbl as a2,tbl as a3 SET a1.l=a2.l+1,a1.r=a2.l+2,a1.level=a2.level+1,a2.r=a2.r+2,a3.r=a3.r+2 WHERE a1.parent_id=a2.id AND a2.l<a3.r AND a1.id=?';
/* 子のlに親の1+1、子のrに親のl+2,子のlevelに親のlevel+1親のrを2増やす、親のlより大きいrを2増やす */
PREPARE stmt from @sql;
EXECUTE stmt USING @id;
SET @sql='UPDATE tbl as a1,tbl as a2,tbl as a3 SET a3.l=a3.l+2 WHERE a1.parent_id=a2.id AND a2.l<a3.l and a3.id!=a1.id AND a1.id=?';
/* 親の1より大きいlの内、子以外のものを2増やす */
PREPARE stmt from @sql;
EXECUTE stmt USING @id;
END IF;
UNTIL done END REPEAT;
CLOSE CUR;
END
といった定義になったので問題なく成功したように思えます!
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/06/05 01:24
2017/06/05 03:14
2017/06/05 03:49
2017/06/05 03:56
2017/06/05 04:19
2017/06/05 04:54
退会済みユーザー
2017/06/05 15:42
2017/06/05 16:23
2017/06/05 16:26
2017/06/06 00:27
2017/06/06 12:10
2017/06/06 12:53 編集
2017/06/07 03:46
2017/06/07 11:18
2017/06/07 12:04
2017/06/08 00:20
2017/06/08 17:05