使用SQL查询重新编号列表中的项目?

时间:2011-03-20 03:37:45

标签: mysql sql

查询:

$consulta = "UPDATE `list` 
                SET `pos` = $pos 
              WHERE `id_item` IN (SELECT id_item 
                                    FROM lists 
                                   WHERE pos = '$item' 
                                ORDER BY pos DESC 
                                   LIMIT 1)
                AND id_usuario = '$us' 
                AND id_list = '$id_pl'";

问题是,这个查询在foreach中,它想要更新列表中项目的顺序。在我这样之前:

$consulta = "UPDATE `list` 
                SET `pos` = $pos
              WHERE `$pos` = '$item' 
                AND id_usuario = '$us' 
                AND id_list = '$id_pl'";

但是当我更新pos 2 - > 1,然后1 - > 2,结果是2次2而没有1 ...

此查询是否有解决方案?

1 个答案:

答案 0 :(得分:1)

重新编号列表中的项目非常棘手。当您使用多个单独的SQL语句重新编号列表中的项目时,它甚至更加棘手。

您的内部子选择语句也未正确约束。您需要一个额外的条件,例如:

AND id_list = '$id_pl'

可能有很多方法可以做到这一点,但可能最简单的方法如下。我假设:

  • 未示出的foreach循环以所需的顺序生成$pos值(1,2,...)
  • $id_pl的值对于循环
  • 是常量
  • foreach循环为每次迭代提供$us$item的值
  • $id_pl$us$item的组合唯一标识list表格中的行
  • 不用担心
  • 超过100 pos个值
  • 您可以围绕语句序列使用显式事务

建议的解决方案有两个阶段:

  1. 为每一行分配100 + pos以将其置于新位置
  2. 从每个pos减去100
  3. 这种技术避免了关于是否已经调整了位置的行被同一查询重新读取的任何复杂问题。

    循环内部:

    foreach ...
        ...$pos, $item, $us...
    
        UPDATE list 
           SET pos = $pos + 100
         WHERE id_item = '$item' 
           AND id_usuario = '$us' 
           AND id_list = '$id_pl'
           AND pos < 100
    end foreach
    
    UPDATE list
       SET pos = pos - 100
     WHERE id__list = '$id_pl';
    

    如果您不知道列表的大小,可以在循环中指定负pos值,并在循环后转换为正值,或者转换为许多其他等效映射中的任何一个。关键是要更新表,以便循环中的新pos号与旧数字不相交,然后在循环后调整新值。

    替代技术创建一个临时表,将旧数字映射到new,然后执行单个UPDATE语句,该语句将旧pos值更改为单个操作中所有行的new值。这可能更有效,特别是如果映射表可以作为查询生成,但这取决于重新编号是否是算法。所示的技术虽然有点笨拙,但可以用于任意重新编号。