我QUES
在 mysql 数据库中有一个表。
该表有一列BODY
目前不是唯一的。
该表有很多行,我确信目前它们BODY
本质上是唯一的,但未定义为属性。
如何更新BODY
具有唯一定义为属性的列?
有人可以建议正确的 sql 查询吗?
谢谢
下面是一些示例 SQL 语句,可以帮助您入门。这假定这body
是一个字符类型列,并且您希望“保留”尽可能多的现有值,并附加一个唯一的字符串以使其“更加独特”。
-- find values of `body` that are "duplicated" in the table
SELECT q.body
, COUNT(1) as cnt_
FROM ques q
GROUP BY q.body
HAVING COUNT(1) > 1
该查询只是为我们提供了body
“重复”的特定值,以及共享该值的行数。我们需要能够识别具有这些唯一值的行,因此我们可以运行如下查询:
-- find all rows that have one of the "duplicated" values
SELECT s.id
, s.body
FROM (SELECT q.body
FROM ques q
WHERE q.body IS NOT NULL
GROUP BY q.body
HAVING COUNT(1) > 1
) r
JOIN ques s ON s.body = r.body
这些是我们需要更新的行。body
为了使这些唯一,我们可以为每一行的列分配一个新的唯一值。如果没有任何“新”值与表中已存在的值重复,我们将拥有唯一值。
更新语句示例:
-- append unique value to end of each body value
UPDATE (SELECT q.body
FROM ques q
WHERE q.body IS NOT NULL
GROUP BY q.body
HAVING COUNT(1) > 1
) r
JOIN ques s ON s.body = r.body
SET s.body = CONCAT(s.body,'<!--',s.id,'-->');
在这里,我们将一个值“附加”到现有主体值的末尾。我们可以利用表中保证不为空且唯一的现有列。AUTO_INCREMENT 主键列是合适的候选者。(我们可以让语句生成一个唯一的整数。)
注意:不能保证我们分配的新值body
与数据库中已经存在的值不同。我们只是识别现有的重复项,然后应用更改以使这些值彼此唯一。我们真的需要回过头来,再次检查重复值。
另请注意,这里没有检查body
列的最大长度,即每个现有值的末尾是否有“空间”来附加给定格式的字符串。所以那里还有改进的空间,检查现有body
值的大小(使用LENGTH()
orCHAR_LENGTH()
函数)并将其与列定义进行比较。
此外,如果有 2 行具有重复值,我们实际上只需要更新其中的一行,我们可以将其中的一行保留为现有值。示例查询现在不执行此操作,但可以执行此操作。
但这应该足以让您入门。
当然,一旦你的值是唯一的,你会想要在这个列上添加一个 UNIQUE 约束,以防止将来创建重复项。
这演示了我们如何保持一行的 body 值不变。(相应的 UPDATE 语句会将该IF()
表达式分配给 body 列。)
-- show new values for body, leave the value for one row unchanged
SELECT s.id
, s.body AS old_val
, IF(s.id = q.min_id, s.body, CONCAT(s.body,'<!--',s.id,'-->')) AS new_val
FROM (SELECT q.body
, MIN(q.id) AS min_id
FROM ques q
WHERE q.body IS NOT NULL
GROUP BY q.body
HAVING COUNT(1) > 1
) r
JOIN ques s ON s.body = r.body
ALTER TABLE QUES ADD UNIQUE (BODY).
在这里阅读精美的手册。