【问题标题】:How to remove special characters in column with MySQL?如何使用 MySQL 删除列中的特殊字符?
【发布时间】:2019-06-04 22:08:28
【问题描述】:

我参加了一个项目,遇到了别人设计的不好,我们有一个表叫task,每个task有很多用户,task表如下:

+----------------+---------------+------+-----+---------+-------+
| Field          | Type          | Null | Key | Default | Extra |
+----------------+---------------+------+-----+---------+-------+
| id             | varchar(40)   | NO   | PRI | NULL    |       |
| name           | varchar(100)  | YES  |     | NULL    |       |
| task_users     | varchar(1000) | YES  |     | NULL    |       |

并且用户像aaa,bbb,ccc一样存储在task_users列中,这意味着将许多用户ID放在一个列中,我知道这是一个非常糟糕的设计,但由于它是一个旧项目,我无法修改表格设计.

现在我有一个问题,如果用户被删除了,如何将其从task_users 列中删除?

用户id是由UUID生成的,长度固定,32个字符,所以每个用户id都是唯一的,比如40cf5f01eb2f4d2c954412f27b3bf6eb,但问题是用户id可能出现在task_users的任意位置列,所以我不知道如何删除它

aaa,40cf5f01eb2f4d2c954412f27b3bf6eb,bbb -- in center
40cf5f01eb2f4d2c954412f27b3bf6eb,aaa,bbb -- in head
aaa,bbb,40cf5f01eb2f4d2c954412f27b3bf6eb -- in end

当删除用户id时,更新后的结果是这样的

   aaa,bbb

我想知道我们可以使用一个更新sql来删除指定的用户id并且仍然保持相同的数据格式吗?

注意:我是在MySQL存储过程中做的,附加变量可能会有帮助,但我还是想只用一个sql来做,MySQL版本是5.0

提前致谢!

【问题讨论】:

  • 您可以使用REGEXP_REPLACE() 函数将指定的用户标识符替换为空字符串。
  • @Alexander 你能举个例子吗?我考虑过使用正则表达式,但关键是如何保持相同的格式,不仅仅是简单地用空替换它,因为这会添加重复的,
  • 对不起,该功能从 MySQL 8.0 开始可以使用
  • @Alexander 没关系,我对这种糟糕的桌子设计感到非常痛苦

标签: mysql sql mysql-5.0


【解决方案1】:

我认为我们可以通过一个查询来做到这一点:

UPDATE yourTable
SET task_users = SUBSTRING(
    REPLACE(CONCAT(',', task_users, ','), CONCAT(',', uid, ','), ','),
    2,
    LENGTH(task_users) - LENGTH(uid) - 1)
WHERE task_users REGEXP CONCAT('[[:<:]]', uid, '[[:>:]]');

这是一个演示链接(用于测试目的):

Demo

这个答案使用了一个技巧,我们将逗号附加到task_users 字符串的开头和结尾。然后,我们还通过在其开头和结尾附加逗号来比较给定的用户 ID。如果找到匹配项,我们只用一个逗号替换。但是,这使得替换仍然带有它的开始和结束逗号,所以我们使用子字符串操作删除那些。

抛开 SQL Olympics 不谈,希望您能从这些答案的复杂性中看出,在 SQL 数据库中处理 CSV 数据确实是一件令人头疼的事情。也许您甚至可以将此页面用作向您的同事证明表格设计需要更改的证据。

【讨论】:

  • 哦,这很聪明。与您看到的使用 XPath 搜索 HTML 类属性类似,即将整个字符串包装在分隔符中。
  • @Phil 我无法使用您的 SQLFiddle 演示(典型行为),但我确实使用 Rextester。如果您有兴趣,请查看演示链接。
  • SQLFiddle 大部分时间都很脆弱,但这里是你的答案作为演示 ~ sqlfiddle.com/#!9/bd4bb/1(使用 UPDATE 而不是 SELECT)
  • @TimBiegeleisen 这就是我想要的答案,非常感谢!
【解决方案2】:

试试这个CASE 表达式,其中uid 是存储过程的参数...

UPDATE `task` SET `task_users` = CASE
  -- at the start
  WHEN `task_users` LIKE CONCAT(uid, ',%')
    THEN REPLACE(`task_users`, CONCAT(uid, ','), '')
  -- at the end
  WHEN `task_users` LIKE CONCAT('%,', uid)
    THEN REPLACE(`task_users`, CONCAT(',', uid), '')
  -- in the middle
  WHEN `task_users` LIKE CONCAT('%,', uid, ',%')
    THEN REPLACE(`task_users`, CONCAT(',', uid, ','), ',')
  -- only that user
  ELSE ''
END
WHERE `task_users` LIKE CONCAT('%', uid, '%');

演示~http://sqlfiddle.com/#!9/1d2baa/1


“四问”答案如下

-- only that user
UPDATE `task`
SET `task_users` = ''
WHERE `task_users` = uid;

-- at start
UPDATE `task`
SET `task_users` = REPLACE(`task_users`, CONCAT(uid, ','), '')
WHERE `task_users` LIKE CONCAT(uid, ',%');

-- at end
UPDATE `task`
SET `task_users` = REPLACE(`task_users`, CONCAT(',', uid), '')
WHERE `task_users` LIKE CONCAT('%,', uid);

-- in the middle
UPDATE `task`
SET `task_users` = REPLACE(`task_users`, CONCAT(',', uid, ','), ',')
WHERE `task_users` LIKE CONCAT('%,', uid, ',%');

演示~http://sqlfiddle.com/#!9/8e9b9bb/1

【讨论】:

  • 感谢您的回答,您的解决方案需要四个单独的 sql,在我的问题中,我想知道我们是否可以只使用一个 sql 来做到这一点
  • @lucumt,可以在custom procedure中使用多个sql查询。
  • @lucumt 我已经用一个潜在的single-query" 解决方案更新了我的答案(尚未测试)
  • 好的,现在测试一下。在 MySQL 5.6 上运行良好
【解决方案3】:

您可以使用以下表达式将指定的用户标识符替换为空字符串:

SET @userID = '40cf5f01eb2f4d2c954412f27b3bf6eb';

UPDATE `task`
SET task_users = REGEXP_REPLACE(task_users, CONCAT('(,', @userID, '|', @userID, ',?)'), '');

或添加WHERE 子句过滤记录以进行更新:

UPDATE `task`
SET task_users = REGEXP_REPLACE(task_users, CONCAT('(,', @userID, '|', @userID, ',?)'), '');
WHERE task_users RLIKE CONCAT('(^|,)', @userID,'(,|$)')

注意REGEXP_REPLACE() 函数是在 MySQL 8.0 中添加的。

【讨论】:

  • 对不起我的数据库版本是 5.0
  • 您的LIKE 版本可能存在问题,如果@userName 恰好也是另一个用户名的子字符串。请改用带有字边界的REGEXP。但是在这里建议使用正则表达式替换通常是个好主意。
  • @TimBiegeleisen OP 说它们都是唯一的 32 个字符串,因此误报的可能性为零
  • @Phil 感谢您的澄清,但总的来说,对于将来阅读此问题的其他人来说,这可能是他的一个问题。
  • @TimBiegeleisen 当然,这很有意义,而且我敢肯定许多其他糟糕的 CSV 实现不享受独特的固定长度的奢华价值观。我的答案与这个问题相同
猜你喜欢
  • 2021-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-27
  • 2011-11-20
  • 1970-01-01
  • 1970-01-01
  • 2016-11-30
相关资源
最近更新 更多