2016-10-13 51 views
3

不要問爲什麼(因爲答案是'我們完全奇怪和bepsoke設置...'),但我需要在不知道密鑰名稱的情況下刪除表中的唯一密鑰(如果存在) - 僅列出組成密鑰的列。Mysql:刪除一個唯一的密鑰,如果存在 - 但不知道密鑰的名稱或它是否存在

例如我有這個表

CREATE TABLE `my_table` (
          `id` binary(36) NOT NULL, 
          `username` char(12) NOT NULL DEFAULT '', 
          `password` char(32) NOT NULL DEFAULT '', 
          `role` char(1) NOT NULL, 
          PRIMARY KEY (`id`), 
          UNIQUE KEY `username_2` (`username`,`role`), 
          UNIQUE KEY `username` (`username`), 
          UNIQUE KEY `username_3` (`username`), 
          UNIQUE KEY `username_4` (`username`), 
          ) 

,我想放棄了(username,role)關鍵,但不是別人(雖然只有當它的存在! - 的時候,我得到了它,它可能已經被刪除)

現在我知道如何刪除一個關鍵的時候,我知道了約束名

ALTER TABLE `my_table` DROP KEY `name_of_my_key` 

,我知道如何檢查一個唯一的密鑰存在

SELECT EXISTS (SELECT constraint_name 
       FROM INFORMATION_SCHEMA.table_constraints 
       WHERE table_name = 'my_table' AND constraint_type='UNIQUE'); 

但是,當我只知道構成唯一密鑰的列時,這仍然無法幫助我。

感謝您的幫助......當我知道一個鍵存在,我怎麼能僅知道哪些列推導constraint_name命令(S)組成的約束,讓我放棄呢?注意約束名稱,因爲mySQL允許您重複添加相同的密鑰,如上面3個相同的(username)密鑰。

我發現的唯一的東西是文章,如Drop Foreign Key without knowing the name of the constraint? 它似乎只顯示如何獲取約束名稱,不能以編程方式標識要刪除的約束。

最後,如果有人知道爲什麼地獄的MySQL將允許你反覆添加相同的鍵(非主),以表我會洗耳恭聽。 MySQL,你太瘋狂了。

+0

也許,'DISTINCT'關鍵字會有幫助嗎?無論哪種方式,這是一種奇怪的想法後面的數據庫結構的邏輯,我想出了一個直接的答案。 (就像爲什麼要動態地改變表格一樣) – Xorifelse

+0

我確實說過不要問爲什麼;)但是既然你問過......如果你(或者以前的某個人給你留下了一個作業)使用相同的表格設置數據庫,將副本分發到1000個不同的地方,然後爲它們部署各種補丁。所以我們知道有一些有限制,有些則沒有,並且我們無法確定限制的命名。難道你不喜歡成爲一名開發者... –

回答

0

在@ shadow的關於key_column_usage和序號位置的提示的幫助下,我現在創建了這個漂亮的存儲過程,它接受一個表,鍵定義(逗號分隔的列列表)和數據庫。然後它檢查該鍵定義是否存在唯一鍵並生成SQL以刪除它們。

我只生產了SQL這裏,以避免人們越來越運行此過程的破壞性操作,只是刪除初始從@sqlstmt「選擇」,如果你真的想要它做的業務。

也可以修改這個在密鑰類型採取作爲一個參數,而不是僅僅依靠硬編碼UNIQUE

CREATE PROCEDURE sp_drop_unique_key_if_exists 
(
given_table VARCHAR(64), 
given_key  TEXT, -- In comma sep form '(col1, col2, ...)' note the brackets are important! 
db    VARCHAR(64) 
) 
BEGIN 

DECLARE drop_constraints TEXT; 
DECLARE dbase    VARCHAR(64); 

SET dbase = IFNULL(db, 'my_db'); 

SELECT  group_concat('DROP KEY `',unique_constraints, '`') 
      INTO drop_constraints 
    FROM    
    (SELECT  IF(REPLACE(given_key, ' ', '') 
         = CONCAT('(', GROUP_CONCAT(kcu.column_name ORDER BY ordinal_position), ')'), 
         tc.constraint_name, null) 
        AS unique_constraints 
     FROM  INFORMATION_SCHEMA.table_constraints tc 
     INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu 
        ON kcu.constraint_name = tc.constraint_name 
        AND kcu.constraint_schema = tc.constraint_schema 
     WHERE  tc.table_name = given_table AND tc.constraint_schema = dbase 
        AND tc.constraint_type='UNIQUE' 
     GROUP BY tc.constraint_name 
    ); 

-- drop the key or keys 
IF drop_constraints IS NOT NULL THEN 
    SET @sqlstmt = CONCAT('SELECT \"ALTER TABLE ',dbase,'.', given_table, ' ',drop_constraints,'\"'); 
    PREPARE st FROM @sqlstmt; 
    EXECUTE st; 
    DEALLOCATE PREPARE st; 
ELSE 
    SELECT CONCAT('Cannot find key ', given_key, ' on ', given_table) DropUniqueKeyErrorMessage; 
END IF; 

END $$ 
1

INFORMATION_SCHEMA.KEY_COLUMN_USAGE表保存其中的字段組成的索引的信息。

可以返回,涉及到給定表與下面的查詢指定的字段指數(或指數)的名稱。存在子查詢確保索引具有兩個字段,而不存在則確保索引沒有任何其他字段。進一步的限制,例如順序位置也可以包含在查詢中。

select CONSTRAINT_NAME 
from INFORMATION_SCHEMA.KEY_COLUMN_USAGE t1 
where TABLE_NAME='my_table' 
    and CONSTRAINT_SCHEMA='myshema' 
    and COLUMN_NAME='username' 
    and exists (select 1 
       from INFORMATION_SCHEMA.KEY_COLUMN_USAGE t2 
       where TABLE_NAME='my_table' 
        and CONSTRAINT_SCHEMA='myshema' 
        and COLUMN_NAME='role' 
        and t2.CONSTRAINT_NAME=t1.CONSTRAINT_NAME 
        and t2.CONSTRAINT_SCHEMA=t1.CONSTRAINT_SCHEMA) 
    and not exists (select 1 
        from INFORMATION_SCHEMA.KEY_COLUMN_USAGE t2 
        where TABLE_NAME='my_table' 
         and CONSTRAINT_SCHEMA='myshema' 
         and COLUMN_NAME NOT IN ('username','role') 
         and t2.CONSTRAINT_NAME=t1.CONSTRAINT_NAME 
         and t2.CONSTRAINT_SCHEMA=t1.CONSTRAINT_SCHEMA) 

但是,上述查詢只返回要刪除的索引的名稱(如果有的話)。您需要動態連接sql命令以使用prepared statement刪除索引。

+0

真棒感謝key_column_usage是一個很好的發現,你的子查詢很好地解釋。其中一個不涉及的事情是索引中的列的順序(即如果存在的話,它也會找到'(role,username)'鍵),但是你給了我一個前進方向。乾杯。 –

+0

正如我在答案中所寫的那樣:「進一步的限制,比如順序位置也可以包含在查詢中。」如果您點擊文檔鏈接,您會發現ordinal_position列定義了索引中字段的序號位置。只需將它添加到你的where子句。 – Shadow

相關問題