带有CASE语句的MySQL Update SET

时间:2016-12-07 17:30:21

标签: mysql

我一直在使用左右id来处理层次结构树。因此,我的数据库包含parent_idleft_idright_id列等。

我使用sqlite,:memory:database,使用PHPUnit构建了许多测试,这些测试都按预期工作。但是,现在我已经开始在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测试中在树中的Node4之后移动Node3的有效的完整查询是:

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)

但是,我发现通过MySQL数据库(并通过Sequel Pro)运行相同的查询,Node4的right_id没有按原样更新到4,并且住在6

有趣的是,如果我完全从查询中删除left_id部分而不以任何其他方式更改它,则right_id列会更新正确(Node3 right_id变为{ {1}},Node4 6变为right_id)。

关于为什么会出现这种情况的任何想法?

1 个答案:

答案 0 :(得分:0)

在MySQL中,UPDATE语句的SET子句使用引用字段中最多的&#34;当前&#34;(甚至在语句本身内)值。

例如,假设您有一行(f1, f2, f3),其值为(1, 2, 3),并希望&#34;旋转&#34;田野&#39;值。您不能执行UPDATE ... SET f1 = f2, f2 = f3, f3 = f1 ...之类的操作,因为您的最终状态为(2, 3, 2)。相反,您可以执行...SET @i = f1, f1 = f2, f2 = f3, f3 = @i ... 之类的操作(如果您在UPDATE中可以分配给会话变量的回忆并不存在缺陷。)

此示例可能对您的特定情况没有帮助,但旨在演示一般行为。