Php SQL:使用CASE语句一次更新1000行

Php SQL:使用CASE语句一次更新1000行,php,sql,sql-update,case-statement,Php,Sql,Sql Update,Case Statement,好的,我想用一个案例陈述来说明这个问题,但我对此感到困惑。基本上,我需要更新大量的行,但只是在“位置”列上。我需要根据每个id\u布局和id\u布局位置,更新所有大于位置值的位置值,该位置值被删除为位置-1 好的,这是这张桌子的图片: 现在假设我删除了带圆圈的行,这将删除position=2,并给出:0、1、3、5、6、7和4。它应该重新定位大于2的位置值,使其看起来像:0、1、2、4、5、6和3 好的,这是我到目前为止在删除行中得到的结果,下面是它的外观(注意:$module_info['c

好的,我想用一个
案例陈述来说明这个问题,但我对此感到困惑。基本上,我需要更新大量的行,但只是在“位置”列上。我需要根据每个id\u布局和id\u布局位置,
更新所有大于位置值的位置值,该位置值被删除为
位置-1

好的,这是这张桌子的图片:

现在假设我删除了带圆圈的行,这将删除position=2,并给出:0、1、3、5、6、7和4。它应该重新定位大于2的位置值,使其看起来像:0、1、2、4、5、6和3

好的,这是我到目前为止在删除行中得到的结果,下面是它的外观(注意:$module_info['clones']=要删除的克隆数组,在上表中没有,因为所有id_clone值都是0,$module_info['id']是我们要删除的id_模块值):

新问题:
在这个
UPDATE
now中必须有某种方式来使用CASE语句。例如,我现在需要根据每个id_布局和每个id_布局_位置将所有位置更新为位置-1。但仅当位置大于该id_布局和id_布局位置值的当前位置时


是否可以在不使用FOREACH循环的情况下执行此操作?

要以不间断的顺序进行更新,可以使用以下方法:

SET @reset := 0; 
UPDATE dp_positions
SET
  positions = 
  CASE          
    WHEN id_layout_position > @reset THEN 
      IF(@pos:=0,NULL, @reset:=id_layout_position)        
    ELSE @pos := @pos + 1    
  END - 1  
ORDER BY id_layout_position, position;
注意:@reset应设置为id\u layout\u位置的最小值,假设您在id\u layout\u位置更改时重新启动计数器,如果情况更复杂,则需要更改时间条件,并且您可能需要更多变量来保存前一行的值。
此外,IF是一个hack,只要您将@pos设置为0而不是其他起始值,它就永远不会为NULL,我只是不知道如何强制mysql计算两个表达式(任何人,有什么优雅的东西吗?)

以上内容已测试,但列/表名称不同(可能会出现重新键入错误)

编辑:我的测试不是很好,上面有一个错误,而且似乎OP需要绕过框架的安全性,所以这里有一个更正和存储过程版本

使用或mysql命令行执行

delimiter //
CREATE PROCEDURE `renumerate`()
BEGIN
SET @pos := -1;
SET @reset := (SELECT MIN(id_layout_position) FROM dp_position);
UPDATE
  dp_positions
SET
  position = 
    CASE          
      WHEN b > @reset THEN 
        IF(@reset:=id_layout_position, @pos:=0, @pos:=0)        
      ELSE @pos := @pos + 1    
    END
ORDER BY id_layout_position, position;
END //
delimiter ;
(在使用phpMyAdmin的情况下,不要使用分隔符语句,而是直接在接口中将分隔符指定为//)。 调用过程时,执行普通SQL

$smcFunc['db_query']('', 'CALL renumerate()');

希望这次我的测试更好。

要以不间断的顺序更新,您可以使用以下命令:

SET @reset := 0; 
UPDATE dp_positions
SET
  positions = 
  CASE          
    WHEN id_layout_position > @reset THEN 
      IF(@pos:=0,NULL, @reset:=id_layout_position)        
    ELSE @pos := @pos + 1    
  END - 1  
ORDER BY id_layout_position, position;
注意:@reset应设置为id\u layout\u位置的最小值,假设您在id\u layout\u位置更改时重新启动计数器,如果情况更复杂,则需要更改时间条件,并且您可能需要更多变量来保存前一行的值。
此外,IF是一个hack,只要您将@pos设置为0而不是其他起始值,它就永远不会为NULL,我只是不知道如何强制mysql计算两个表达式(任何人,有什么优雅的东西吗?)

以上内容已测试,但列/表名称不同(可能会出现重新键入错误)

编辑:我的测试不是很好,上面有一个错误,而且似乎OP需要绕过框架的安全性,所以这里有一个更正和存储过程版本

使用或mysql命令行执行

delimiter //
CREATE PROCEDURE `renumerate`()
BEGIN
SET @pos := -1;
SET @reset := (SELECT MIN(id_layout_position) FROM dp_position);
UPDATE
  dp_positions
SET
  position = 
    CASE          
      WHEN b > @reset THEN 
        IF(@reset:=id_layout_position, @pos:=0, @pos:=0)        
      ELSE @pos := @pos + 1    
    END
ORDER BY id_layout_position, position;
END //
delimiter ;
(在使用phpMyAdmin的情况下,不要使用分隔符语句,而是直接在接口中将分隔符指定为//)。 调用过程时,执行普通SQL

$smcFunc['db_query']('', 'CALL renumerate()');

希望这次我的测试更好。

在删除一行之前,您可以获得它的位置,并减少所有位置较高的行的位置

伪代码:

function deleteRow($id){
  DB::startTransaction()
  try{
    $infos = DB::getData('SELECT position FROM db_positions WHERE id_position = :ID', array(':ID' => $id));
    if(empty($infos)){
      throw("useless ID");
    }
    DB::query('DELETE FROM db_positions WHERE id_position = :ID', array(':ID' => $id));
    DB::query('UPDATE db_positions SET position = position - 1 WHERE position > :position', array(':position' => $infos['position']);
    DB::commit();
  }
  catch(Exception $e){
    DB::rollBack();
  }
}

在删除一行之前,可以获取该行的位置并减少所有位置较高的行的位置

伪代码:

function deleteRow($id){
  DB::startTransaction()
  try{
    $infos = DB::getData('SELECT position FROM db_positions WHERE id_position = :ID', array(':ID' => $id));
    if(empty($infos)){
      throw("useless ID");
    }
    DB::query('DELETE FROM db_positions WHERE id_position = :ID', array(':ID' => $id));
    DB::query('UPDATE db_positions SET position = position - 1 WHERE position > :position', array(':position' => $infos['position']);
    DB::commit();
  }
  catch(Exception $e){
    DB::rollBack();
  }
}

你的问题很难理解……好吧,问题是,我如何在第一个代码示例中使用
CASE语句
,以便我可以更新
位置
列中的所有行,从
0-找到的行总数
中,这些行具有
id\u布局
值和
id\u布局
值,然后对该表中所有不同的
id\u布局
值继续执行此操作?您仍然在询问您所感知的解决方案:如何陈述您实际想要实现的目标,而不是您认为您应该如何实现?好的,当然。我试图在最后一个位置中插入一些内容,但在执行此操作之前,我需要先对所有位置重新排序,因为如果稍后删除某个位置,则位置值将不正确。也就是说,位置值可以如下所示:0、1、4、6、5、8。当然,这是小规模的。我正在更大规模地做这件事。因此,我需要在最后插入新位置之前对其进行重新排序。为什么不只是显示您的表的外观,并解释您要更新的内容,然后这里的人就会知道如何更新,无论是否有案例。您的问题很难理解…好的,问题是,如何在第一个代码示例中使用
CASE语句
,以便我可以更新
位置
列中的所有行,从
0-找到的行总数
中,这些行具有
id\u布局
值和
id\u布局
值,然后对该表中所有不同的
id\u布局
值继续执行此操作?您仍然在询问您所感知的解决方案:如何陈述您实际想要实现的目标,而不是您认为您应该如何实现?好的,当然。我试图在最后一个位置中插入一些内容,但在执行此操作之前,我需要先对所有位置重新排序,因为如果稍后删除某个位置,则位置值将不正确。也就是说,位置值可能看起来像