2016-10-13 8 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'); 
が存在するかどうかを確認する方法を知っています210

しかし、これは私が一意のキーを構成する列だけを知っているときは、私には役に立たない。

あなたの助けをお待ちしています...キーが存在することがわかったら、どの列が制約を作成してドロップすることができるかだけを知ることからconstraint_nameを派生させることができますか?制約名は、上記の3つの同じ(username)キーのような同じキーを繰り返し追加できるため、制約名を通知します。

私が見つけた唯一の事は、Drop Foreign Key without knowing the name of the constraint? のようなものです。これは、制約名を取得する方法を示しているだけで、ドロップする制約をプログラムでは特定できません。

最後に、誰かがmySQLが同じキー(プライマリではない)を繰り返してテーブルに追加できる理由を知っていれば、私はすべての耳になるでしょう。 MySQL、あなたはとても狂っています。

+0

おそらく、「DISTINCT」キーワードは役に立ちますか?いずれにしても、db構造のロジックの背後にある私は、まっすぐな答えを出すために奇妙な思考の一種です。 (なぜ動的にテーブルを変更したいのですか) – Xorifelse

+0

私は言ったことはありませんでした;)しかし、あなたが尋ねると、あなたはテーブルを動的に変更したいと思います。ジョブ)同じテーブルを持つデータベースをセットアップし、異なる場所の1000にレプリカを配布した後、さまざまなパッチを配備しました。だから私たちは制約を持っているものもあれば、そうでないものもあることを知っています。デベロッパーであることが大好きではありませんか? –

答えて

0

key_column_usageと序数の位置に関する@shadowのヒントの助けを借りて、テーブル、キー定義(カンマで区切られた列のリスト)、およびデータベースを取るこの素晴らしいストアドプロシージャを作成しました。次に、そのキー定義に固有​​のキーが存在するかどうかをチェックし、それらをドロップするSQLを生成します。

このプロシージャを実行している人が破壊的な操作をしないようにするために、ここでSQLを作成しましたが、実際にビジネスを行う場合は、単に@sqlstmtから最初の 'select'を削除してください。

ハードコードされた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テーブルは、どのフィールドがインデックスを構成しているかの情報を保持します。

指定したテーブルに関連するインデックスの名前を、指定したフィールドで次のクエリで返すことができます。 existsサブクエリは、インデックスに両方のフィールドがあることを確認し、存在しない場合は、インデックスに他のフィールドがないことを確認します。序数などの追加の制限もクエリに組み込むことができます。

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) 

ただし、上記のクエリは、削除するインデックスの名前(存在する場合)のみを返します。 prepared statementを使用してインデックスを削除するには、sqlコマンドを動的に連結する必要があります。

+0

恐ろしいおかげでkey_column_usageは良い発見であり、あなたのサブクエリーはうまく説明されています。これが扱わないことの1つは、インデックス内の列の順序です(つまり、存在する場合は '(role、username) 'キーも見つかるでしょう)が、私には道筋を与えています。乾杯。 –

+0

私が答えて書いたように、「順序の位置などのさらなる制約もクエリに組み込むことができます」ドキュメントへのリンクをクリックすると、ordinal_position列がインデックス内のフィールドの順序位置を定義することがわかります。あなたのwhere句に追加するだけです。 – Shadow

関連する問題