Mysql :如果存在唯一键,则删除 - 但不知道键的名称或它是否存在
Mysql : Drop a unique key if exists -- but without knowing name of the key or whether it exists
不要问为什么(因为答案是 'our totally weird and bepsoke setup...'),但我需要在不知道密钥名称的情况下在 table(如果存在)上放置一个唯一密钥 - - 仅组成键的列。
例如我有这个 table
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 会允许您重复将相同的密钥(非主密钥)添加到 table,我会洗耳恭听。 MySQL,你太疯狂了
INFORMATION_SCHEMA.KEY_COLUMN_USAGEtable保存了哪些字段构成索引的信息。
您可以 return 与给定 table 相关的一个或多个索引的名称,其中包含以下查询的给定字段。 exists 子查询确保索引有两个字段,not 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)
但是,上面的查询只 returns 您要删除的索引的名称(如果有的话)。您需要使用 prepared statement.
动态连接 sql 命令以删除索引
借助@shadow 关于 key_column_usage 和序数位置的提示,我现在创建了这个漂亮的存储过程,它接受 table,键定义(逗号分隔的列列表) 和数据库。然后它检查该键定义是否存在唯一键并生成 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 $$
不要问为什么(因为答案是 'our totally weird and bepsoke setup...'),但我需要在不知道密钥名称的情况下在 table(如果存在)上放置一个唯一密钥 - - 仅组成键的列。
例如我有这个 table
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 会允许您重复将相同的密钥(非主密钥)添加到 table,我会洗耳恭听。 MySQL,你太疯狂了
INFORMATION_SCHEMA.KEY_COLUMN_USAGEtable保存了哪些字段构成索引的信息。
您可以 return 与给定 table 相关的一个或多个索引的名称,其中包含以下查询的给定字段。 exists 子查询确保索引有两个字段,not 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)
但是,上面的查询只 returns 您要删除的索引的名称(如果有的话)。您需要使用 prepared statement.
动态连接 sql 命令以删除索引借助@shadow 关于 key_column_usage 和序数位置的提示,我现在创建了这个漂亮的存储过程,它接受 table,键定义(逗号分隔的列列表) 和数据库。然后它检查该键定义是否存在唯一键并生成 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 $$