2016-12-07 11 views
0

私は左と右のIDを使って階層ツリーに取り組んできました。だから私のデータベースはparent_id,left_idright_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_id4に更新されておらず、6のままです。私は、クエリから完全left_idセクションを削除し、他の方法でそれを変更しない場合

興味深いことに、right_id列が正しく更新されない(ノード3 right_id6になると、ノード4 right_id4なります)。

なぜそうなのでしょうか?

+0

質問を深く検討する時間がありません。しかし、あなたのUPDATEロジックは、CASEがright_idを設定し、新しいleft_idの値を使用し、CASEが新しいleft_idとright_idの値を使用することを考慮に入れていることを考慮に入れていますか? – Uueerdo

+0

Uh、no。彼らはしない。私は正直に言うと、私は決して物事に出くわすことはないだろうし、sqliteで期待していた通りに動作することを考えれば、列が順番に更新されるとは考えていなかった...私は多くのコード改訂が必要です。 – AJEllender

+0

同様に、ほとんどの私の経験はMySQLで行われていたので、私はMSSQLに移行してUPDATEで "古い"値を使用するのは少し驚きでした。 – Uueerdo

答えて

0

MySQLでは、UPDATEステートメントのSET句は、参照されるフィールドの最も「最新の」(ステートメント自体内であっても)値を使用します。

たとえば、値(1, 2, 3)の行(f1, f2, f3)があり、フィールドの値を「回転」させたいとします。最後の状態は(2, 3, 2)となるので、UPDATE ... SET f1 = f2, f2 = f3, f3 = f1 ...のようなことはできません。 (あなたがUPDATEでセッション変数に割り当てることができ、私の記憶に欠陥がない場合。)その代わり、あなたは...SET @i = f1, f1 = f2, f2 = f3, f3 = @i ...ような何かを行うことができ

この例では、特定の場合には有用ではないかもしれないが、実証することを意図しています一般的な行動。