我有一张桌子:
id name
1 a
2 a
3 a
4 b
5 b
6 c
我正在寻找一个更新语句,将name
列更新为:
id name
1 a
2 a-2
3 a-3
4 b
5 b-2
6 c
在SQL Server
我会使用:
;with cte as(select *, row_number() over(partition by name order by id) rn from table)
update cte set name = name + '-' + cast(rn as varchar(10))
where rn <> 1
我在MySQL
非标准查询中并不强大。
我可以在MySQL
中执行类似的操作吗?
答案 0 :(得分:4)
在MySQL中,您可以使用变量来模拟ROW_NUMBER
窗口函数:
SELECT id, CONCAT(name, IF(rn = 1, '', CONCAT('-', rn))) AS name
FROM (
SELECT id, name,
@rn := IF(name = @n, @rn + 1,
IF(@n := name, 1, 1)) AS rn
FROM mytable
CROSS JOIN (SELECT @rn := 0, @n := '') AS vars
ORDER BY name, id) AS t
UPDATE
你可以使用:
UPDATE mytable AS t1
SET name = (
SELECT CONCAT(name, IF(rn = 1, '', CONCAT('-', rn))) AS name
FROM (
SELECT id, name,
@rn := IF(name = @n, @rn + 1,
IF(@n := name, 1, 1)) AS rn
FROM mytable
CROSS JOIN (SELECT @rn := 0, @n := '') AS vars
ORDER BY name, id) AS t2
WHERE t1.id = t2.id)
您还可以UPDATE
使用JOIN
语法:
UPDATE mytable AS t1
JOIN (
SELECT id, rn, CONCAT(name, IF(rn = 1, '', CONCAT('-', rn))) AS name
FROM (
SELECT id, name,
@rn := IF(name = @n, @rn + 1,
IF(@n := name, 1, 1)) AS rn
FROM mytable
CROSS JOIN (SELECT @rn := 0, @n := '') AS vars
ORDER BY name, id) AS x
) AS t2 ON t2.rn <> 1 AND t1.id = t2.id
SET t1.name = t2.name;
后者可能比前者更快,因为它执行的UPDATE
操作更少。
答案 1 :(得分:4)
你可以这样做:
UPDATE YourTable p
JOIN(SELECT t.id,t.name,count(*) as rnk
FROM YourTable t
INNER JOIN YourTable s on(t.name = s.name and t.id <= s.id)
GROUP BY t.id,t.name) f
ON(p.id = f.id)
SET p.name = concat(p.name,'-',f.rnk)
WHERE rnk > 1
这将基本上使用join和count来获得与ROW_NUMBER()相同的内容,并且只更新那些结果超过1的人(意味着第二个,第三个ETC不包括第一个)
答案 2 :(得分:2)
下一个查询将以更少的工作量完成数据库:
UPDATE
tab AS tu
INNER JOIN
-- result set containing only duplicate rows that must to be updated
(
SELECT
t.id,
COUNT(*) AS cnt
FROM
tab AS t
-- join the same table by smaller id and equal value. That way you will exclude rows that are not duplicated
INNER JOIN
tab AS tp
ON
tp.name = t.name
AND
tp.id < t.id
GROUP BY
t.id
) AS tc
ON
tu.id = tc.id
SET
tu.name = CONCAT(tu.name, '-', tc.cnt + 1)