我一直在使用左右id来处理层次结构树。因此,我的数据库包含parent_id
,left_id
和right_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
)。
关于为什么会出现这种情况的任何想法?
答案 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中可以分配给会话变量的回忆并不存在缺陷。)
此示例可能对您的特定情况没有帮助,但旨在演示一般行为。