【问题标题】:MySQL Update a column with values combined from target column and another columnMySQL 使用从目标列和另一列组合的值更新列
【发布时间】:2019-03-14 13:19:18
【问题描述】:

我想更新列user,用id 替换最后6 个字符并用零填充。 user 列下的所有键的格式为 ^[A-Z]{2}[0-9]{8}$。例如,这里有一些示例数据:

MariaDB [test]> SELECT * FROM users ORDER BY id ASC LIMIT 3;
+----+------------+
| id | user       |
+----+------------+
|  1 | AS12491264 |
|  2 | LQ10240183 |
|  3 | MR12037108 |
+----+------------+
3 rows in set (0.00 sec)

预期结果是:

+----+------------+
| id | user       |
+----+------------+
|  1 | AS12000001 |
|  2 | LQ10000002 |
|  3 | MR12000003 |
+----+------------+

我解决了以下两个查询,但都失败了:

UPDATE users AS u
SET u.user = (
  SELECT
    CONCAT(
      SUBSTRING(s.user, 0, 4),
      LPAD(s.id, 6, '0')
    )
  FROM users AS s
  WHERE s.id = u.id
);
UPDATE users AS u
INNER JOIN (
  SELECT
    s.id AS id,
    CONCAT(
      SUBSTRING(s.user, 0, 4),
      LPAD(s.id, 6, '0')
    ) AS data
  FROM users AS s
) AS s ON s.id = u.id
SET u.user = s.data;

都失败并给出这个结果:

+----+--------+
| id | user   |
+----+--------+
|  1 | 000001 |
|  2 | 000002 |
|  3 | 000003 |
+----+--------+

这是数据库架构(取自 mysqldump):

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user` varchar(64) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `user` (`user`)
) ENGINE=InnoDB AUTO_INCREMENT=8964 DEFAULT CHARSET=utf8;

我在 MariaDB 10.1.38 上运行。

【问题讨论】:

  • 你真的把那个查询复杂化了
  • 我强烈建议在 SELECT 语句中测试表达式,然后再将它们合并到 UPDATE 中。
  • @spencer7593 顾名思义,它实际上是一个测试数据库。我有原始的mysqldump 可以在一个 shell 命令中恢复所有更改。
  • 测试数据库没关系。我的建议是一样的。表达式可以在SELECT 语句中进行测试,这允许我们返回当前值以及新值,当我们寻求帮助时,这可以作为向同事演示的有用。
  • SUBSTRING() 从 1 开始,而不是 0。但请参阅 Nick 的回答。

标签: mysql sql-update mariadb inner-join


【解决方案1】:

这应该做你想做的:

UPDATE users
SET user = CONCAT(LEFT(user,4), LPAD(id, 6, '0'))

输出:

id  user
1   AS12000001
2   LQ10000002
3   MR12000003

Demo on dbfiddle

更新

如果用户列具有可变长度,您可以使用此查询仅替换最后 6 个字符,该查询使用 CHAR_LENGTH 确定字符串的长度并从中减去 6 以确定左侧有多少个字符保持。我们使用CHAR_LENGTH 而不是LENGTH,因此查询仍然适用于多字节字符编码。

UPDATE users
SET user = CONCAT(LEFT(user,CHAR_LENGTH(user)-6), LPAD(id, 6, '0'))

Demo on dbfiddle

【讨论】:

  • 这满足“保留前 4 个字符”的规范,这与“替换后 6 个字符”(在一般情况下)不同;
  • @spencer7593 "All keys under column user are in the format ^[A-Z]{2}[0-9]{8}$" 这意味着它们有 10 个字符长,因此保留前 4 个字符与替换后 6 个字符相同
  • @spencer7593 添加了一个额外的查询,它将替换最后 6 个字符,并且与长度无关(假设它至少有 6 个字符长)。
  • 我对您的解决方案很好,我真的只是评论规范的更准确描述,在更一般的情况下,当我们没有保证字符长度为 10 时。对于第二个查询,LENGTH 函数适用于大多数字符集,但对 [A-Z0-9] 字符使用多个字节的编码除外,例如 ucs2utf16utf32。对于这些字符集,我们希望使用CHAR_LENGTH 函数(对字符进行操作),而不是LENGTH 函数(对字节进行操作)。
  • @spencer7593 没问题,你提出了一个有效的观点;答案对它更好。也感谢CHAR_LENGTH 的评论,我也更新了答案(并使演示使用多字节编码)
猜你喜欢
  • 2014-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-24
  • 1970-01-01
  • 2010-11-22
  • 2021-07-20
  • 1970-01-01
相关资源
最近更新 更多