私は左と右のIDを使って階層ツリーに取り組んできました。だから私のデータベースはparent_id
,left_id
とright_id
の列を持っています。CASE文を使ったMySQLのアップデート
PHPUnitを使って、sqlite、:memory:データベースを使っていくつかのテストを構築しました。これらはすべて期待どおりに動作します。しかし、MySQLデータベースでクエリを使用するようになったので、予期しない動作をしています。
roles
テーブルなどで簡略化されたテストデータベースを考える:
id parent_id left_id right_id
Node1 1 null 1 8
Node2 2 1 2 7
Node3 3 2 3 4
Node4 4 2 5 6
作業は、SQLiteのテストでは、ツリーにノード4の後にノード3を移動するための完全なクエリは次のとおりです。ただし
UPDATE `roles` SET
`left_id` = (CASE
WHEN (`roles`.`left_id` >= 3 AND `roles`.`right_id` <= 4) THEN (`left_id` + 2)
WHEN (`roles`.`left_id` > 3 AND `roles`.`right_id` <= 6) THEN (`left_id` - 2)
WHEN (`roles`.`left_id` <= 5 AND `roles`.`right_id` >= 6) THEN (`left_id` - 2)
ELSE `left_id` END),
`right_id` = (CASE
WHEN (`roles`.`left_id` >= 3 AND `roles`.`right_id` <= 4) THEN (`right_id` + 2)
WHEN (`roles`.`left_id` > 3 AND `roles`.`right_id` <= 6) THEN (`right_id` - 2)
WHEN (`roles`.`left_id` < 3 AND `roles`.`right_id` > 4) THEN (`right_id` - 2)
ELSE `right_id` END),
`parent_id` = (CASE
WHEN `roles`.`id` = 3 THEN 2
ELSE `parent_id` END),
`depth` = (CASE
WHEN (`roles`.`left_id` >= 3 AND `roles`.`right_id` <= 4) THEN (depth + 0)
ELSE `depth` END),
`updated_at` = '2016-12-07 15:50:17'
WHERE (left_id BETWEEN 3 AND 6 OR right_id BETWEEN 3 AND 6)
、I MySQLデータベース(Sequel Pro経由)で同じクエリを実行すると、Node4のright_id
は4
に更新されておらず、6
のままです。私は、クエリから完全left_id
セクションを削除し、他の方法でそれを変更しない場合
興味深いことに、right_id
列が正しく更新されない(ノード3 right_id
が6
になると、ノード4 right_id
は4
なります)。
なぜそうなのでしょうか?
質問を深く検討する時間がありません。しかし、あなたのUPDATEロジックは、CASEがright_idを設定し、新しいleft_idの値を使用し、CASEが新しいleft_idとright_idの値を使用することを考慮に入れていることを考慮に入れていますか? – Uueerdo
Uh、no。彼らはしない。私は正直に言うと、私は決して物事に出くわすことはないだろうし、sqliteで期待していた通りに動作することを考えれば、列が順番に更新されるとは考えていなかった...私は多くのコード改訂が必要です。 – AJEllender
同様に、ほとんどの私の経験はMySQLで行われていたので、私はMSSQLに移行してUPDATEで "古い"値を使用するのは少し驚きでした。 – Uueerdo