更改值时重新排列数字序列

nle07wnf  于 2021-06-21  发布在  Mysql
关注(0)|答案(2)|浏览(339)

我正在开发一个在数据库中存储树的应用程序。应用程序是使用cakephp2.x和jstree3.2.1构建的
保存数据的模式如下: id -自动递增id,对于树的每个节点都是唯一的 parent_id -元素的父id; null 如果没有父元素(顶级元素)。 lft , rght -使用cakephp的树行为,它使用修改的前序树遍历。这些代表 lft 以及 rght 价值观。 name -节点的文本名称 pos -从0开始的整数,用于确定节点在其父节点下的位置。
我遇到的问题是“调整”所有的 pos 更新树中节点的位置时的元素。
例如,考虑以下数据:

id    |    parent_id    |    name    |     pos
--------------------------------------------------
149   |    NULL         |    Foo     |     0
150   |    149          |    A       |     0
151   |    149          |    B       |     1
152   |    149          |    C       |     2
153   |    149          |    D       |     3
154   |    149          |    E       |     4
155   |    149          |    F       |     5

从视觉上看,如下所示:


b
c
d
e
f
现在如果我拖放“e”,那么它在“b”和“c”之间。。。


b
e(移动
c
d
f
... 我需要更新 pos 在我的数据库中的值,对于“foo”的子对象。
当发生拖放时,jstree为我提供了:
这个 id 我所移动的元素。”“e”应该是 154 .
这个 parent_id 那个“e”已经放在下面了。在这种情况下 149 因为它仍然是“foo”的子元素,但理论上可以移动到树上的任何其他元素下。
这个 pos (位置)它被投进去了。这些值从0开始,因此在上面的示例中,移动“e”后,它将进入 pos = 2 .
理解节点可以向上或向下任意方向拖动是很重要的,但是jstree只提供 pos 相对于它在父节点下的位置(以及 parent_id 以及 id ).
所以我可以用新的 pos 对于“e”:

>UPDATE tree SET pos = 2 WHERE id = 154 AND parent_id = 149;

id    |    parent_id    |    name    |     pos
--------------------------------------------------
149   |    NULL         |    Foo     |     0
150   |    149          |    A       |     0
151   |    149          |    B       |     1
152   |    149          |    C       |     2
153   |    149          |    D       |     3
154   |    149          |    E       |     2 (*updated*)
155   |    149          |    F       |     5

我的问题是如何重新安排另一个 pos 价值观。例如,“c”现在应该有一个 pos 的价值 4 .
github上有一些代码展示了移动节点时如何保存数据的示例,但我无法理解(尽管我花了好几天的时间)或将其改编为cakephp。实际上,提供的大部分代码都是不必要的,因为cake负责生成 lft 以及 rght 价值观。所以我想知道的是如何使用php/mysql将数字“移位”或“调整”回数字序列
我提供这个以防有帮助:
这个 pos 值按顺序在每个父节点下(父节点id)。因此,如果我们有另一个父元素“bar”,它有子元素“xx”、“yy”和“zz”,则数据可能如下所示。请注意 pos 值是。
所以查询应该只调整 pos 对于给定的 parent_id 在任何特定的时间。在前面的示例中,我只想重新排序 pos 为了 parent_id = 149 -假设我正在移动节点“e”。

id    |    parent_id    |    name    |     pos
--------------------------------------------------
149   |    NULL         |    Foo     |     0
150   |    149          |    A       |     0
151   |    149          |    B       |     1
152   |    149          |    C       |     2
153   |    149          |    D       |     3
154   |    149          |    E       |     4
155   |    149          |    F       |     5
906   |    NULL         |    Bar     |     0
907   |    906          |    XX      |     0
908   |    906          |    YY      |     1
909   |    906          |    ZZ      |     2
dzjeubhm

dzjeubhm1#

weltschmerz的回答似乎很有效。
不过,我会使用一个存储过程,将它们全部重新编号,并在将项“拖放”到新位置后调用它。比如:

DELIMITER $$

DROP PROCEDURE IF EXISTS `renumberPos`$$
CREATE PROCEDURE `renumberPos`(
  in itemID int,
  in parentID int,
  in mPos int
)
declare cnt int default 0;
declare n int default 0;
declare pk int;
declare cur CURSOR for select id from tree 
                       where parent_id = parentID 
                       and id != itemID
                       order by pos;
BEGIN
  select count(*) into n from tree where parent_id = parentID

  open cur;

  WHILE cnt <= n+1 DO
    IF cnt = mPos then
      FETCH cur into pk;
      update tree set 
      pos = cnt 
      where id = pk;
      cnt = cnt + 1;
    END IF;

    FETCH cur into pk;
    update tree set 
    pos = cnt 
    where id = pk;
    cnt = cnt + 1;
  END WHILE;

  close cur;
END$$

DELIMITER ;

那你就把它叫做。。。

$sql = "CALL renumberPos($movedItemId, $itemParentID, $posMovedTo)";
if(mysqli_query($link, $sql)){
  echo "Procedure sorted the positions...";
}else{
  echo "ERROR: Couldn't execute $sql. " . mysqli_error($link);
}
holgip5t

holgip5t2#

您有足够的信息来修改同级节点的位置。
如果154已移动到位置2:

UPDATE tree SET pos = 2 WHERE id = 154 AND parent_id = 149;

我们要“删除”节点,然后再“插入”它。大致如下:

-- remove node from current position by updating nodes to the right to fill the gap
UPDATE tree SET pos = pos - 1 
       WHERE parent_id = 149 
       AND pos > (SELECT pos FROM tree WHERE id = 154);

-- insert node in new position by making space for it
UPDATE tree SET pos = pos + 1 WHERE parent_id = 149 AND pos >= 2;
UPDATE tree SET pos = 2 WHERE id = 154;

通常,在父节点之间移动节点时:

:node_id       - id of node being moved
:new_parent_id - id of the new parent
:new_position  - new position

-- remove node from current position and update siblings to the right
UPDATE tree AS t
      JOIN tree AS n ON n.id = :node_id
      SET t.pos = t.pos - 1
      WHERE t.parent_id = n.parent_id AND t.pos > n.pos;

-- make space for new node under new parent
UPDATE tree
  SET pos = pos + 1
  WHERE parent_id = :new_parent_id
  AND pos >= :new_position;

-- update new position and new parent
UPDATE tree
  SET pos = :new_position, parent_id = :new_parent_id
  WHERE id = :node_id;

相关问题