2015-04-05 88 views
1

我有一個帶有1000個人員記錄的MySQL數據庫,通常帶有重複項。MySQL:用新值替換特定外鍵的所有實例

對於每個至少有一個副本的情況,我希望能夠刪除除一個之外的所有副本,然後使用我沒有的副本更新對這些已刪除外鍵的引用。

例如,我們看到的下面Star Lord兩個實例:

+-----------------------+ 
|  `users`  | 
+------+----------------+ 
| id | name   | 
+------+----------------+ 
| 1 | Star Lord  | 
+------+----------------+ 
| 2 | Star Lord  | 
+------+----------------+ 
| 3 | Iron Man  | 
+------+-----+----------+ 

+-----------------------+ 
|  `messages`  | 
+------+-----+----------+ 
| from | to | text  | 
+------+-----+----------+ 
| 1 | 5 | hi  | 
+------+-----+----------+ 
| 2 | 5 | how r u | 
+------+-----+----------+ 
| 5 | 2 | Good, u? | 
+------+-----+----------+ 

這兩個表應該成爲:

+-----------------------+ 
|  `users`  | 
+------+----------------+ 
| id | name   | 
+------+----------------+ 
| 1 | Star Lord  | 
+------+----------------+ 
| 3 | Iron Man  | 
+------+-----+----------+ 

+-----------------------+ 
|  `messages`  | 
+------+-----+----------+ 
| from | to | text  | 
+------+-----+----------+ 
| 1 | 5 | hi  | 
+------+-----+----------+ 
| 1 | 5 | how r u | 
+------+-----+----------+ 
| 5 | 1 | Good, u? | 
+------+-----+----------+ 

可以這樣做?我很高興根據需要使用PHP。

我發現下面的,但它只是用於查找外鍵的使用,而不是取代實例特定鍵值:MySQL: How to I find all tables that have foreign keys that reference particular table.column AND have values for those foreign keys?

獎勵積分

可能是一個需要有額外的數據合併在users表中。例如,ID爲1的Star Lord可能填寫了phone字段,但ID號爲2的Star Lord的字段爲email

最壞情況:他們都有有一個字段,有衝突的數據。

+0

除非你要進行人工干預,獎勵積分是近不可解。你可以做空值,但除非你能爲每次衝突提出一個規則,否則不行。 – 2015-04-05 08:38:42

回答

0

我喜歡真正有條不紊,雖然你可以把它寫在一個複雜的查詢中,這是一個優化,除非它很明顯,不必要的。

首先備份您的數據庫:) Create a table來保存您將要保留的用戶的ID。

寫些說

Insert into Keepers Select keep_id From (Select Min(id) as keep_id,`name` From `users`) 

之後,它只是一些更新連接。

例如

UPDATE 
    `messages` m JOIN 
    keepers k 
     ON k.keeper_id = m.from 
SET m.from = k.keeper_id 

UPDATE 
    `messages` m JOIN 
    keepers k 
     ON k.keeper_id = m.to 
SET m.to = k.keeper_id 

然後擺脫用戶的你不想

Delete `users` 
from `users` u 
outer join keepers on k.keeper_id = u.id 
where i.id is null 

When一切都很好比如你有相同數量的消息,你開始,沒有人在談論自己等等。

Delete the keepers table. 

語法未檢查,但它應該是關閉的。

2

我建議:

  1. 創建正確的數據表。一個很好的出發點可能是:

    CREATE TABLE users_new LIKE users; 
    ALTER TABLE users_new ADD UNIQUE (name); 
    
    INSERT INTO users_new 
        (id, name, phone, email) 
    SELECT MIN(id), name, GROUP_CONCAT(phone), GROUP_CONCAT(email) 
    FROM  users 
    GROUP BY name; 
    

    需要注意的是,由於「獎勵積分」下的「最壞情況」的觀察,你可能想歸檔的基本users數據之前手動驗證此表的內容(我建議不要永久刪除,以防萬一)。

  2. 更新現有的國外關係:

    UPDATE messages 
        JOIN (users uf JOIN users_new unf USING (name)) ON uf.id = messages.from 
        JOIN (users ut JOIN users_new unt USING (name)) ON ut.id = messages.to 
    SET messages.from = unf.id, 
         messages.to = unt.id 
    

    如果你有很多表的更新,你可以緩存的結果加入users之間users_new - 或者:

    • 在舊users表內的new_id列:

      ALTER TABLE users ADD new_id BIGINT UNSIGNED; 
      
      UPDATE users JOIN users_new USING (name) 
      SET users.new_id = users_new.id; 
      
      UPDATE messages 
          JOIN users uf ON uf.id = messages.from 
          JOIN users ut ON ut.id = messages.to 
      SET messages.from = uf.new_id, 
           messages.to = ut.new_id; 
      
    • 或者在一個新的(臨時)表:

      CREATE TEMPORARY TABLE newid_cache (
          PRIMARY KEY(old_id), 
          KEY(old_id, new_id) 
      ) ENGINE=MEMORY 
      SELECT users.id AS old_id, users_new.id AS new_id 
      FROM users JOIN users_new USING (name); 
      
      UPDATE messages 
          JOIN newid_cache nf ON nf.old_id = messages.from 
          JOIN newid_cache nt ON nt.old_id = messages.to 
      SET messages.from = nf.new_id, 
           messages.to = nt.new_id; 
      
  3. 要麼與users_new更換users,否則修改應用程序以使用新表代替舊的。

    ALTER TABLE users  RENAME TO users_old; 
    ALTER TABLE users_new RENAME TO users; 
    
  4. 根據需要更新任何外鍵約束。

+0

放入隊友備份一步,我知道它應該是可怕顯而易見的,但... – 2015-04-05 08:42:31

+0

@TonyHopkinson:但是原始表絕不會被修改(除可選,用於添加'new_id'列,並將最終更名步驟) - 底層數據從未被觸及。 – eggyal 2015-04-05 08:43:38

+0

然後他們刪除users_old,一天後有人響起,說'我的所有消息'已經消失。然後你進入完全災難模式。你已經足夠做這件事了,粗心大意,像我這樣的無知者,需要一個支持者。 :( – 2015-04-05 08:50:27

相關問題