2016-02-21 37 views
4

我有一個表:更新重複的行

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這樣做嗎?

回答

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 

這基本上是用加入和計數,以獲得相同的ROW_NUMBER(),並且只更新那些誰擁有更多然後1次的結果(指第二,第三ETC排除第一)

+0

謝謝你的回答!讓我試試這個。 –

+0

@GiorgiNakeuri沒問題,讓我知道如果你有任何錯誤 – sagi

+0

不,它更新只有1行,並設置計數接近行數7438,而行數是7412. –

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) 

Demo here

您還可以使用UPDATEJOIN語法:

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

+0

你好Giorgos!我們可以爲'update'編輯它嗎? –

+0

我已經嘗試過最後一條語句,它完美地工作。 –

+0

@GiorgiNakeuri很高興我能夠幫助你。乾杯Giorgi! –

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)