使用递增的文本值更新表中的所有行

时间:2019-02-03 00:04:20

标签: mysql sql loops

如何使用SQL使用递增的文本值更新表中每一行的列。

我有一个表,该表包含名为ej_number的列,这是唯一的标识符。字段格式为EJnnnn,即EJ后跟四位数字。我导入的数据不包含ej_number的值,但是某些新行确实对其进行了设置。我想从EJ0001开始更新未设置ej_number的每一行。稍后我将解决重复问题。

我第一拳是在PHP中循环完成的,但是意识到由于行数的原因服务器会超时,所以我决定在SQL中这样做。

我的第一个想法是使用循环,但是我的研究发现不建议逐行更新,特别是因为我看到的唯一方法是使用游标,因此也不建议这样做。

我能够在一条语句中做到这一点-下面的代码可以工作,但是它会生成警告(使用MySQL Workbench)。

SET @next_number = 0;
UPDATE ej_details
    SET ej_number = CASE
        WHEN ej_number IS NULL THEN (
            CONCAT('EJ', LPAD((@next_number:=@next_number+1), 4, '0')))
        ELSE ej_number
    END;

该语句可以执行我想要的操作,但是会生成以下警告:

  

受影响的692行,1警告:1287在表达式中设置用户变量已被弃用,并将在以后的版本中删除。请改为在单独的语句中设置变量。匹配的行:692已更改:692警告:1

我想知道如何最好地做到这一点而不使用不推荐使用的功能。我查看并找到了大量的逐行解决方案,但看不到不是逐行的替代方案,可能是因为我不知道该问什么。

1 个答案:

答案 0 :(得分:0)

我想你只是想要

SET @next_number = 0;

UPDATE ej_details
    SET ej_number = CONCAT('EJ',
                           LPAD( (@next_number:=@next_number+1), 4, '0'
                               )
                          )
    WHERE ej_number IS NULL;

这比较简单,但不会更改错误。

如果您想在一个呼叫中执行此操作,则:

UPDATE ej_details CROSS JOIN
       (SELECT @next_number := 0) params
    SET ej_number = CONCAT('EJ',
                           LPAD( (@next_number:=@next_number+1), 4, '0'
                               )
                          )
    WHERE ej_number IS NULL;

不幸的是,如果该列被声明为unique,那么您将无法解析“稍后”的重复值。

如果您想在没有错误的情况下解决此问题,则需要一个主键/唯一列:

UPDATE ej_details ed JOIN
       (SELECT ed.*,
               ROW_NUMBER() OVER (ORDER BY ej_number) as seqnum
        FROM ej_details ed2
        WHERE ej_number IS NULL
       ) ed2
       ON ed2.? = ed.?  -- the primary key goes here
    SET ed.ej_number = CONCAT('EJ', LPAD(ed2.seqnum, 4, '0')
                             );

但是,此版本不向后兼容。

如果他们真的从MySQL 9中删除了变量,我会感到惊讶。这会破坏很多代码。