我需要一个在嵌套集中移动节点及其所有子节点的 MySQL 查询。我找到了这个网站,但这个功能看起来很不合逻辑——没有嵌套集合模型universeid
或treeid
在嵌套集合模型中,而且代码本身比感觉需要的要长。我在表中得到的唯一额外列是parent
.
我不能只是删除并再次添加节点,因为它会丢失它的 ID。
我需要一个在嵌套集中移动节点及其所有子节点的 MySQL 查询。我找到了这个网站,但这个功能看起来很不合逻辑——没有嵌套集合模型universeid
或treeid
在嵌套集合模型中,而且代码本身比感觉需要的要长。我在表中得到的唯一额外列是parent
.
我不能只是删除并再次添加节点,因为它会丢失它的 ID。
我明白了,这个话题已经很老了,但无论如何它仍然没有答案。我从谷歌来到这里,并没有找到这个问题的直接答案。
因此,经过一些研究,我发现了非常简单的解决方案。
一切,我们需要移动我们的节点是:节点左右位置,新的父节点正确位置。然后可以通过四个简单的步骤将节点移动到新位置:
这是理论,现在 - 这个算法在 MySQL 中的实现(使用 PHP 的例子):
-- step 0: Initialize parameters.
SELECT
@node_id := 1, --put there id of moving node
@node_pos_left := 0, --put there left position of moving node
@node_pos_right := 1, --put there right position of moving node
@parent_id := 2, --put there id of new parent node (there moving node should be moved)
@parent_pos_right := 4; --put there right position of new parent node (there moving node should be moved)
SELECT
@node_size := @node_pos_right - @node_pos_left + 1; -- 'size' of moving node (including all it's sub nodes)
-- step 1: temporary "remove" moving node
UPDATE `list_items`
SET `pos_left` = 0-(`pos_left`), `pos_right` = 0-(`pos_right`)
WHERE `pos_left` >= @node_pos_left AND `pos_right` <= @node_pos_right;
-- step 2: decrease left and/or right position values of currently 'lower' items (and parents)
UPDATE `list_items`
SET `pos_left` = `pos_left` - @node_size
WHERE `pos_left` > @node_pos_right;
UPDATE `list_items`
SET `pos_right` = `pos_right` - @node_size
WHERE `pos_right` > @node_pos_right;
-- step 3: increase left and/or right position values of future 'lower' items (and parents)
UPDATE `list_items`
SET `pos_left` = `pos_left` + @node_size
WHERE `pos_left` >= IF(@parent_pos_right > @node_pos_right, @parent_pos_right - @node_size, @parent_pos_right);
UPDATE `list_items`
SET `pos_right` = `pos_right` + @node_size
WHERE `pos_right` >= IF(@parent_pos_right > @node_pos_right, @parent_pos_right - @node_size, @parent_pos_right);
-- step 4: move node (ant it's subnodes) and update it's parent item id
UPDATE `list_items`
SET
`pos_left` = 0-(`pos_left`)+IF(@parent_pos_right > @node_pos_right, @parent_pos_right - @node_pos_right - 1, @parent_pos_right - @node_pos_right - 1 + @node_size),
`pos_right` = 0-(`pos_right`)+IF(@parent_pos_right > @node_pos_right, @parent_pos_right - @node_pos_right - 1, @parent_pos_right - @node_pos_right - 1 + @node_size)
WHERE `pos_left` <= 0-@node_pos_left AND `pos_right` >= 0-@node_pos_right;
UPDATE `list_items`
SET `parent_item_id` = @parent_id
WHERE `item_id` = @node_id;
请注意 - SQL 代码中仍然可能存在一些语法错误,因为我实际上在 PHP 中使用了这个算法,如下所示:
$iItemId = 1;
$iItemPosLeft = 0;
$iItemPosRight = 1;
$iParentId = 2;
$iParentPosRight = 4;
$iSize = $iPosRight - $iPosLeft + 1;
$sql = array(
// step 1: temporary "remove" moving node
'UPDATE `list_items`
SET `pos_left` = 0-(`pos_left`), `pos_right` = 0-(`pos_right`)
WHERE `pos_left` >= "'.$iItemPosLeft.'" AND `pos_right` <= "'.$iItemPosRight.'"',
// step 2: decrease left and/or right position values of currently 'lower' items (and parents)
'UPDATE `list_items`
SET `pos_left` = `pos_left` - '.$iSize.'
WHERE `pos_left` > "'.$iItemPosRight.'"',
'UPDATE `list_items`
SET `pos_right` = `pos_right` - '.$iSize.'
WHERE `pos_right` > "'.$iItemPosRight.'"',
// step 3: increase left and/or right position values of future 'lower' items (and parents)
'UPDATE `list_items`
SET `pos_left` = `pos_left` + '.$iSize.'
WHERE `pos_left` >= "'.($iParentPosRight > $iItemPosRight ? $iParentPosRight - $iSize : $iParentPosRight).'"',
'UPDATE `list_items`
SET `pos_right` = `pos_right` + '.$iSize.'
WHERE `pos_right` >= "'.($iParentPosRight > $iItemPosRight ? $iParentPosRight - $iSize : $iParentPosRight).'"',
// step 4: move node (ant it's subnodes) and update it's parent item id
'UPDATE `list_items`
SET
`pos_left` = 0-(`pos_left`)+'.($iParentPosRight > $iItemPosRight ? $iParentPosRight - $iItemPosRight - 1 : $iParentPosRight - $iItemPosRight - 1 + $iSize).',
`pos_right` = 0-(`pos_right`)+'.($iParentPosRight > $iItemPosRight ? $iParentPosRight - $iItemPosRight - 1 : $iParentPosRight - $iItemPosRight - 1 + $iSize).'
WHERE `pos_left` <= "'.(0-$iItemPosLeft).'" AND i.`pos_right` >= "'.(0-$iItemPosRight).'"',
'UPDATE `list_items`
SET `parent_item_id` = "'.$iParentItemId.'"
WHERE `item_id`="'.$iItemId.'"'
);
foreach($sql as $sqlQuery){
mysql_query($sqlQuery);
}
另请注意,该代码可能会被优化,但为了更好的可读性,我将保留它。如果您在多用户系统中使用嵌套集,还要考虑表锁定。
希望我的信息对任何在我之后寻找解决方案的人有所帮助。也欢迎任何意见和更正。
这是一个解决方案,可让您将节点移动到树中的任何位置,无论是作为兄弟节点还是子节点,只需一个输入参数 - 节点的新左侧位置 (newlpos)。
基本上分为三个步骤:
在 psuedo-sql 中,它看起来像这样:
//
* -- create new space for subtree
* UPDATE tags SET lpos = lpos + :width WHERE lpos >= :newlpos
* UPDATE tags SET rpos = rpos + :width WHERE rpos >= :newlpos
*
* -- move subtree into new space
* UPDATE tags SET lpos = lpos + :distance, rpos = rpos + :distance
* WHERE lpos >= :tmppos AND rpos < :tmppos + :width
*
* -- remove old space vacated by subtree
* UPDATE tags SET lpos = lpos - :width WHERE lpos > :oldrpos
* UPDATE tags SET rpos = rpos - :width WHERE rpos > :oldrpos
*/
:distance 变量是新位置和旧位置之间的距离,:width 是子树的大小,:tmppos 用于跟踪在更新期间移动的子树。这些变量定义为:
// calculate position adjustment variables
int width = node.getRpos() - node.getLpos() + 1;
int distance = newlpos - node.getLpos();
int tmppos = node.getLpos();
// backwards movement must account for new space
if (distance < 0) {
distance -= width;
tmppos += width;
}
有关完整的代码示例,请参阅我的博客:
https://rogerkeays.com/how-to-move-a-node-in-nested-sets-with-sql
如果您喜欢此解决方案,请投票。
我知道这是一个老问题,但我自己只是使用了答案,但用于 SQL Server。如果有人想要,这里是基于接受的答案的 SQL Server 存储过程的代码。
CREATE PROCEDURE [dbo].[Item_Move]
@id uniqueidentifier,
@destinationId uniqueidentifier
AS
BEGIN
SET NOCOUNT ON;
declare @moverLeft int,
@moverRight int,
@destinationRight int,
@node_size int
-- step 0: Initialize parameters.
SELECT
@moverLeft = leftExtent,
@moverRight = rightExtent
FROM
Item
WHERE
id = @id
SELECT
@destinationRight = rightExtent
FROM
Item
WHERE
id = @destinationId
SELECT
@node_size = @moverRight - @moverLeft + 1; -- 'size' of moving node (including all it's sub nodes)
-- step 1: temporary "remove" moving node
UPDATE Item
SET leftExtent = 0-(leftExtent), rightExtent = 0-(rightExtent), updatedDate = GETDATE()
WHERE leftExtent >= @moverLeft AND rightExtent <= @moverRight;
-- step 2: decrease left and/or right position values of currently 'lower' items (and parents)
UPDATE Item
SET leftExtent = leftExtent - @node_size, updatedDate = GETDATE()
WHERE leftExtent > @moverRight;
UPDATE Item
SET rightExtent = rightExtent - @node_size, updatedDate = GETDATE()
WHERE rightExtent > @moverRight;
-- step 3: increase left and/or right position values of future 'lower' items (and parents)
UPDATE Item
SET leftExtent = leftExtent + @node_size, updatedDate = GETDATE()
WHERE leftExtent >= CASE WHEN @destinationRight > @moverRight THEN @destinationRight - @node_size ELSE @destinationRight END;
UPDATE Item
SET rightExtent = rightExtent + @node_size, updatedDate = GETDATE()
WHERE rightExtent >= CASE WHEN @destinationRight > @moverRight THEN @destinationRight - @node_size ELSE @destinationRight END;
-- step 4: move node (and it's subnodes) and update it's parent item id
UPDATE Item
SET
leftExtent = 0-(leftExtent) + CASE WHEN @destinationRight > @moverRight THEN @destinationRight - @moverRight - 1 ELSE @destinationRight - @moverRight - 1 + @node_size END,
rightExtent = 0-(rightExtent) + CASE WHEN @destinationRight > @moverRight THEN @destinationRight - @moverRight - 1 ELSE @destinationRight - @moverRight - 1 + @node_size END,
updatedDate = GETDATE()
WHERE leftExtent <= 0-@moverLeft AND rightExtent >= 0-@moverRight;
UPDATE Item
SET parentId = @destinationId, updatedDate = GETDATE()
WHERE id = @id;
END
在嵌套集设计中移动子树非常昂贵且复杂。
您应该考虑使用不同的设计来表示树。
例如,如果您使用路径枚举设计,则将每个节点的直接祖先列表存储为连接字符串。
id path
1 1/
2 1/2/
3 1/3/
4 1/3/4/
5 1/3/5/
然后移动一个子树(比如节点 3 移动到节点 2 的子节点):
UPDATE Tree t
JOIN Tree node2 ON (node2.id = 2)
JOIN Tree node3 ON (node3.id = 3)
SET t.path = CONCAT(node2.path, REPLACE(t.path, node3.path, node2.path))
WHERE t.path LIKE CONCAT(node3.path, '%');
有关在以下位置存储和使用分层数据的信息,请参阅我博客中的文章MySQL
:
要在这样的表中移动整个分支,您只需要更新根的parent
(单行)
您需要创建一个函数:
CREATE FUNCTION hierarchy_connect_by_parent_eq_prior_id(value INT) RETURNS INT
NOT DETERMINISTIC
READS SQL DATA
BEGIN
DECLARE _id INT;
DECLARE _parent INT;
DECLARE _next INT;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET @id = NULL;
SET _parent = @id;
SET _id = -1;
IF @id IS NULL THEN
RETURN NULL;
END IF;
LOOP
SELECT MIN(id)
INTO @id
FROM t_hierarchy
WHERE parent = _parent
AND id > _id;
IF @id IS NOT NULL OR _parent = @start_with THEN
SET @level = @level + 1;
RETURN @id;
END IF;
SET @level := @level - 1;
SELECT id, parent
INTO _id, _parent
FROM t_hierarchy
WHERE id = _parent;
END LOOP;
END
并在查询中使用它:
SELECT CONCAT(REPEAT(' ', level - 1), CAST(hi.id AS CHAR)) AS treeitem, parent, level
FROM (
SELECT hierarchy_connect_by_parent_eq_prior_id(id) AS id, @level AS level
FROM (
SELECT @start_with := 0,
@id := @start_with,
@level := 0
) vars, t_hierarchy
WHERE @id IS NOT NULL
) ho
JOIN t_hierarchy hi
ON hi.id = ho.id
我有一个存储过程,它将嵌套集中的节点移动到新的父节点。我在名为“somedb”的 MySQL / InnoDB 数据库中使用名为“category”的表。当然,如果目标是您要移动的类别的子类别,则此过程会搞砸,因此请确保您没有尝试将节点嵌入到自身内部。我将把它作为练习留给读者,以使这个过程在这种情况下安全。
CREATE PROCEDURE `somedb`.`moveCatParent` (IN cat_a VARCHAR(45), IN cat_b VARCHAR(45))
BEGIN
START TRANSACTION;
/* cat_b.lft + 1 is the destination. */
SELECT @destination := (lft + 1)
FROM category
WHERE name = cat_b;
SELECT @cat_a_width := ((rgt - lft) + 1)
FROM category
WHERE name = cat_a;
/* Rip this table a new cat_a sized hole inside cat_b. */
UPDATE category SET rgt = rgt + @cat_a_width WHERE rgt >= @destination;
UPDATE category SET lft = lft + @cat_a_width WHERE lft >= @destination;
SELECT @cat_a_lft := lft, @cat_a_rgt := rgt
FROM category
WHERE name = cat_a;
SELECT @diff := @destination - @cat_a_lft;
/* Move cat_a and all inhabitants to new hole */
UPDATE category SET rgt = rgt + @diff WHERE rgt BETWEEN @cat_a_lft AND @cat_a_rgt;
UPDATE category SET lft = lft + @diff WHERE lft BETWEEN @cat_a_lft AND @cat_a_rgt;
/* Close the gap created when we moved cat_a. */
UPDATE category SET rgt = rgt - @cat_a_width WHERE rgt >= @cat_a_lft;
UPDATE category SET lft = lft - @cat_a_width WHERE lft >= @cat_a_lft;
COMMIT;
END
我相信用两个额外的列来存储原始节点的右值和左值(以及所有后续子节点)可以简化算法。我已经用铅笔和纸处理了这些例子,所以如果你发现算法中有任何漏洞,请告诉我。
目标节点(您要移动的节点的新父节点)是 tNode。目标节点的左值为 tNode.L,右值为 tNode.R。同样,您要移动的节点是 mNode,mNode 的左右值是 mNode.L 和 mNode.R。两个额外的列是 mNode.SL 和 mNode.SR
所以总而言之,我们有 4 列用于操作 R、L、SL 和 SR
计算
delta1 = (mNode.R - mNode.L) + 1
将 mNode 原始 L 和 R 保存到 SL 和 SR 列中
- For All L between mNode.L and mNode.R
mNode.SL = mNode.L ; mNode.L = 0 ;
- For All R between mNode.L and mNode.R
mNode.SR = mNode.R ; mNode.R = 0 ;
Do For all Nodes
IF L > mNode.SR
L = L + delta1
IF R > mNode.SR
R = R + delta1
现在 mNode 从 Tree 中分离出来,并且 Tree 在没有 mNode 的情况下进行了调整。
计算
delta2 = (tNode.R - mNode.SL)
Do for all Nodes
IF L >= tNode.R
L = L + delta1
IF R >= tNode.R
R = R + delta1
现在我们已经调整了树(和目标节点)以接受被删除的节点数。
在 tNode 处附加 mNode 并重置 SL/SR 列值
Do for all Nodes
IF SL between mNode.SL and mNode.SR
L = mNode.SL + delta2 ; mNode.SL = 0 ;
IF SR between mNode.SL and mNode.SR
R = mNode.SR + delta2 ; mNode.SR = 0 ;
在所有这些步骤之后,我们应该将 mNode 移动到 tNode 下。
感谢您将 lft 和 rgt 转换为负面对应物的想法。我在这里发布了一个更通用的方法:Move node in Nested Sets tree。
queryBatch() 函数将查询包含在事务中。
很简单,先定义一个存储过程:
CREATE DEFINER=`root`@`localhost` PROCEDURE `move_item`(
IN itemId BIGINT, IN kind SMALLINT,
IN newSiblingId BIGINT UNSIGNED, IN newSiblingKind SMALLINT, IN newParentId BIGINT UNSIGNED,
IN jobId BIGINT UNSIGNED, IN companyId BIGINT UNSIGNED,
OUT outSucess SMALLINT UNSIGNED)
proc_label:BEGIN
接下来我们需要一些局部变量:
DECLARE oldLeft, oldRight, newLeft, newRight, itemWidth, moveBy INT UNSIGNED DEFAULT 0;
set outSucess =0;
现在获取我们旧的左右并获取宽度
SELECT `LFT`, `RGT` into oldLeft, oldRight from `nodes` where `ID`=itemId LIMIT 1;
SET itemWidth = oldRight - oldLeft + 1;
现在乘以 -1 将它们“从树中取出”
UPDATE `nodes` SET `RGT`=`RGT`* -1, `LFT`=`LFT`* -1 WHERE ``LFT` BETWEEN oldLeft and oldRight;
下一部分不是必需的,因为没有它,树也可以工作,但它很整洁;缩小旧差距:
-- Update right
UPDATE `nodes` SET `RGT` = `RGT` - itemWidth WHERE `RGT` > oldRight;
-- Update left
UPDATE `nodes` SET `LFT` = `LFT` - itemWidth WHERE `LFT` > oldRight;
现在找到新位置:
SELECT (`RGT`+1) into newLeft from `nodes` where `ID`=newSiblingId LIMIT 1;
-- No sibling, so make it last in parent
IF (newLeft = 0) AND (newParentId != 0) THEN
SELECT `RGT` into newLeft from `nodes` WHERE `ID`=newParentId LIMIT 1;
END IF;
-- If no previous sibling or parent, set to first item in tree
IF (newLeft=0) OR (newLeft=NULL) THEN SET newLeft=1;
END IF;
现在腾出一些空间:
-- Update right
UPDATE `nodes` SET `RGT` = `RGT` + itemWidth WHERE `RGT` >= newLeft;
-- Update left
UPDATE `nodes` SET `LFT` = `LFT` + itemWidth WHERE `LFT` >= newLeft;
最后将移出树的节点移回 * -1,当你在它的时候,也将它们移动到正确的位置:
SET moveBy = OldLeft - NewLeft;
UPDATE `nodes` SET `RGT`=(`RGT`* -1)-moveBy, `LFT`=(`LFT`* -1)-moveBy WHERE `LFT` < 0;
set outSucess =1;
未经测试、粘贴、调整和简化的工作程序。
我知道这篇文章很旧,但我为其他所有会来这里查看解决方案的人发布了这个解决方案。我找到了这个@sedna-soft.de。我测试了 id 并且工作得很好
-- moves a subtree before the specified position
-- if the position is the rgt of a node, the subtree will be its last child
-- if the position is the lft of a node, the subtree will be inserted before
-- @param l the lft of the subtree to move
-- @param r the rgt of the subtree to move
-- @param p the position to move the subtree before
SET @r: , @l: , @p:
update tree
set
lft = lft + if (@p > @r,
if (@r < lft and lft < @p,
@l - @r - 1,
if (@l <= lft and lft < @r,
@p - @r - 1,
0
)
),
if (@p <= lft and lft < @l,
@r - @l + 1,
if (@l <= lft and lft < @r,
@p - @l,
0
)
)
),
rgt = rgt + if (@p > @r,
if (@r < rgt and rgt < @p,
@l - @r - 1,
if (@l < rgt and rgt <= @r,
@p - @r - 1,
0
)
),
if (@p <= rgt and rgt < @l,
@r - @l + 1,
if (@l < rgt and rgt <= @r,
@p - @l,
0
)
)
)
where @r < @p or @p < @l;
# Get Left and Right offsets of both source node (Drag Node) and target node (Drop off Node).
SELECT lft,rgt INTO @sourceNodeLft,@sourceNodeRgt FROM treetest WHERE id=_sourceNodeId;
SELECT lft,rgt INTO @targetNodeLft,@targetNodeRgt FROM treetest WHERE id=_targetNodeId;
# Determine node order direction
SET @direction := IF(@targetNodeLft<@sourceNodeLft,'UP','DOWN');
# Determine with of source node (Drag Node)
SET @width := @sourceNodeRgt - @sourceNodeLft + 1;
# Mark all displaced nodes with negative lft and rgt
UPDATE treetest SET lft = 0-lft, rgt = 0-rgt
WHERE lft >= @targetNodeLft AND rgt <= @targetNodeRgt;
UPDATE treetest SET lft = 0-lft, rgt = 0-rgt
WHERE lft >= @sourceNodeLft AND rgt <= @sourceNodeRgt;
# Update left and right offsets of inner nodes between source (Drag Node)and target (Drop off) node
UPDATE treetest SET lft = (lft + IF(@direction = 'UP',@width,0-@width)),
rgt = (rgt + IF(@direction = 'UP',@width,0-@width))
WHERE lft > IF(@direction = 'UP', @targetNodeLft, @sourceNodeLft)
AND rgt < IF(@direction = 'UP', @sourceNodeLft, @targetNodeLft);
# Update source (Drag) Node and its children offsets
SET @sourceOffset := IF(@direction = 'UP',@targetNodeLft - @sourceNodeLft, @targetNodeRgt - @width - @sourceNodeLft+1);
UPDATE treetest SET lft = 0 - lft + @sourceOffset,
rgt = 0 - rgt + @sourceOffset
WHERE (0-lft) >= @sourceNodeLft AND (0-rgt) <= @sourceNodeRgt;
# Update target (Drop off) node and its children offsets
SET @targetOffset := IF(@direction = 'UP', 0 - @width,@width);
UPDATE treetest SET lft = 0 - (lft + @targetOffset),
rgt = 0 - (rgt + @targetOffset)
WHERE (0-lft) >= @targetNodeLft AND (0-rgt) <= @targetNodeRgt;
已经有很多答案了,但我觉得我的答案可能对某人有用。根据 Roger Keays 的回答(非常感谢!),我为 mySQL 数据库编写了存储过程:
-- to move target before specified node
CREATE DEFINER=`root`@`%` PROCEDURE `move_before`(IN target_id int, before_id int)
BEGIN
SELECT @new_pos := lft FROM dirs WHERE id = before_id;
CALL move(target_id, @new_pos);
END
-- to move target after specified node
CREATE DEFINER=`root`@`%` PROCEDURE `move_after`(IN target_id int, after_id int)
BEGIN
SELECT @new_pos := rgt + 1 FROM dirs WHERE id = after_id;
CALL move(target_id, @new_pos);
END
-- to move target to the specified node
CREATE DEFINER=`root`@`%` PROCEDURE `move_in`(IN target_id int, parent_id int)
BEGIN
SELECT @new_pos := rgt FROM dirs WHERE id = parent_id;
CALL move(target_id, @new_pos);
END
--main procedure to move target before position
CREATE DEFINER=`root`@`%` PROCEDURE `move`(in target_id int, in new_pos int)
BEGIN
SELECT @oldlft := lft, @oldrgt := rgt
FROM dirs
WHERE target_id = id;
SET @width := @oldrgt - @oldlft +1;
SET @distance := new_pos - @oldlft;
SET @tmppos := @oldlft;
IF (@distance <0)
THEN
SELECT @distance := @distance - @width;
SELECT @tmppos := @tmppos + @width;
END IF;
-- create new space for subtree
UPDATE dirs SET lft = lft + @width WHERE lft >= new_pos;
UPDATE dirs SET rgt = rgt + @width WHERE rgt >= new_pos;
-- move subtree into new space
UPDATE dirs SET lft = lft + @distance, rgt = rgt + @distance
WHERE lft >= @tmppos AND rgt < @tmppos + @width;
-- remove old space vacated by subtree
UPDATE dirs SET lft = lft - @width WHERE lft > @oldrgt;
UPDATE dirs SET rgt = rgt - @width WHERE rgt > @oldrgt;
END
$row 是一个数组,代表我必须移动的行;它必须是这样的:
Array ( [lft] => 5 [rgt] => 10 [width] => 6 )
$row2 是代表命运节点的数组;
Array ( [id] => 5 [lft] => 2 [rgt] => 17 [width] => 16 )
...
mysql_query("UPDATE entryCategory SET rgt = rgt + %d - %d, lft = lft + %d - %d WHERE rgt <= %d and lft >= %d;",$row2["rgt"],$row["lft"],$row2["rgt"],$row["lft"],$row["rgt"],$row["lft"]);
mysql_query("UPDATE entryCategory SET rgt = rgt + %d WHERE id=%d;",$row["width"],$row2["id"]);
mysql_query("UPDATE entryCategory SET rgt = rgt - %d, lft = lft - %d WHERE rgt > %d and lft > %d;",$row["width"],$row["width"],$row["rgt"],$row["rgt"]);