5

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

+----------------+---------------+------+-----+---------+-------+
| 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,ccctask_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

提前致谢!

4

3 回答 3

4

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

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, '[[:>:]]');

在此处输入图像描述

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

演示

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

除了 SQL Olympics,希望您能从这些答案的复杂性中看出,在 SQL 数据库中处理 CSV 数据可能会让人头疼。也许您甚至可以将此页面用作向您的同事证明表格设计需要更改的证据。

于 2019-01-10T05:28:58.560 回答
2

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

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 中添加的。

于 2019-01-10T04:40:30.503 回答
2

试试这个CASE表达式 where uidis the argument to your storage procedure...

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

于 2019-01-10T04:32:26.633 回答