簡體   English   中英

MySQL:用新值替換特定外鍵的所有實例

[英]MySQL: Replace all instances of specific foreign key with new value

我有一個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:如何查找所有具有引用特定table.column的外鍵並具有這些外鍵值的表?

獎勵積分

users表中可能需要合並其他數據。 例如,ID為#1的Star Lord可能填寫了phone字段,而ID為2的Star Lord有一個email字段。

最壞的情況:它們都有一個領域,隨着矛盾的數據。

我建議:

  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 

    如果要更新的表很多,則可以緩存usersusers_new之間的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. 適當更新任何外鍵約束。

我喜歡真的有條不紊,盡管您可以在一個復雜的查詢中編寫所有代碼,但這是一種優化,除非很明顯,否則這是不必要的。

首先備份數據庫:) 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.

語法未選中,但應關閉。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM