Mysql 使用空值创建复合唯一索引的首选方法
我的数据库中有以下值: 我想在Mysql 使用空值创建复合唯一索引的首选方法,mysql,sql,indexing,Mysql,Sql,Indexing,我的数据库中有以下值: 我想在tv\u连续剧\u id+name+tv\u季号+tv\u集号上创建一个唯一的键。但是,上述内容不适用于我使用传统方法的目的: ALTER TABLE main_itemmaster ADD UNIQUE KEY (tv_series_id, tv_season_number, tv_episode_number, name) 因为有空值。在数据库级别(而不是查询端)解决这个问题的方法是什么 为了澄清,不允许出现上述情况,因为“97736第4-4-NULL季”重
tv\u连续剧\u id+name+tv\u季号+tv\u集号上创建一个唯一的键
。但是,上述内容不适用于我使用传统方法的目的:
ALTER TABLE main_itemmaster ADD UNIQUE KEY (tv_series_id, tv_season_number, tv_episode_number, name)
因为有空值。在数据库级别(而不是查询端)解决这个问题的方法是什么
为了澄清,不允许出现上述情况,因为“97736第4-4-NULL季”重复了10次。作为最后手段,我考虑实施的解决方案是存储一个额外的字符串列以实现唯一性,因此“97736第4-4季-”用于上述内容。根据要求,我的建议(未经测试):
uniquer背后的算法完全由您决定。我在这里选了一个。您可能需要一个较长的UUID。或者UUID。以时间为基础可能会奏效。您可以将其基于插入行中的MD5值。使用中给出的答案 这将创建一个新列,用于存储电视剧集号,如果电视剧集号为空,则为0。然后在唯一索引中使用tv_series_id、tv_season_编号和名称 触发器将设置新列的值,并防止在更新后插入或变得相同的多个包含空值的相同行 现在,如果多次运行,以下insert语句将抛出重复条目错误:
INSERT INTO main_itemmaster (tv_series_id, name, tv_season_number, tv_episode_number) values (97736, 'Season 4', 4, NULL);
更简单的解决方案(如果您有许多字段,这些字段可能为NULL,并且您仍然希望行是唯一的)
1) 添加唯一的\u散列字段
ALTER TABLE `TABLE_NAME_HERE`
ADD `unique_hash` BIGINT unsigned NOT NULL DEFAULT '0' COMMENT 'JIRA-ISSUE-ID' AFTER `SOME_EXISTING_FIELD`
;
2) 填满它们
UPDATE TABLE_NAME_HERE SET unique_hash=cast(conv(substring(md5(
CONCAT(
IF(field1_id IS NULL, 'NULL',field1_id),'_',
IF(field2_id IS NULL, 'NULL',field2_id),'_',
IF(field3_id IS NULL, 'NULL',field3_id),'_',
IF(field4_id IS NULL, 'NULL',field4_id),'_',
IF(field5_id IS NULL, 'NULL',field5_id),'_'
)
), 1, 16), 16, 10) as unsigned integer);
3) 在bigint上添加唯一索引(它会更快,因为它会更小)
4) 添加触发器
DELIMITER $$
CREATE TRIGGER add_unique_hash BEFORE INSERT ON TABLE_NAME_HERE
FOR EACH ROW
BEGIN
SET NEW.unique_hash = (cast(conv(substring(md5(
CONCAT(
IF(NEW.field1_id IS NULL, 'NULL',NEW.field1_id),'_',
IF(NEW.field2_id IS NULL, 'NULL',NEW.field2_id),'_',
IF(NEW.field3_id IS NULL, 'NULL',NEW.field3_id),'_',
IF(NEW.field4_id IS NULL, 'NULL',NEW.field4_id),'_',
IF(NEW.field5_id IS NULL, 'NULL',NEW.field5_id),'_'
)
), 1, 16), 16, 10) as unsigned integer));
END $$
DELIMITER ;
5) 享受!:)
您将在field1\u id、field2\u id、field3\u id、field4\u id、field5\u id上拥有realy唯一索引。空值只允许出现一次。不需要更改脚本。我很困惑。MySQL允许在唯一索引()中多次出现
NULL
值。所以,你的方法应该有效。@GordonLinoff更新后的最后一句话有助于澄清吗?你必须允许空值吗?您不能为电视剧集号(例如0)设置默认值吗?插入时的触发器,创建一个合成键,然后可以将其包含在合成键中。@evsheino是的,将有空值,例如,电视季或电影没有集号。将其存储为0可能会解决此问题,但会导致许多其他问题。这比原始约束更能强制唯一性吗?(97736,4,NULL,‘第四季’,生成的_id1)和(97736,4,NULL,‘第四季’,生成的_id2)都是唯一的。这个解决方案不会阻止任何唯一的实用程序吗?也就是说,《97736第四季4-4-foo》不会因为额外的“uniquer”专栏而出现两次吗?@RickJames。OP排除了关于其他数据字段的语义信息,而其他信息实际上可能会取消查询这些结果的资格。虽然我的回答严格地回答了这个问题,但我想知道使用不同的自然键的不同方法是否更有意义。瞧,我给了一个战术性的答案,这可能是一个战略问题。
UPDATE TABLE_NAME_HERE SET unique_hash=cast(conv(substring(md5(
CONCAT(
IF(field1_id IS NULL, 'NULL',field1_id),'_',
IF(field2_id IS NULL, 'NULL',field2_id),'_',
IF(field3_id IS NULL, 'NULL',field3_id),'_',
IF(field4_id IS NULL, 'NULL',field4_id),'_',
IF(field5_id IS NULL, 'NULL',field5_id),'_'
)
), 1, 16), 16, 10) as unsigned integer);
ALTER TABLE `TABLE` ADD UNIQUE (`unique_hash`);
DELIMITER $$
CREATE TRIGGER add_unique_hash BEFORE INSERT ON TABLE_NAME_HERE
FOR EACH ROW
BEGIN
SET NEW.unique_hash = (cast(conv(substring(md5(
CONCAT(
IF(NEW.field1_id IS NULL, 'NULL',NEW.field1_id),'_',
IF(NEW.field2_id IS NULL, 'NULL',NEW.field2_id),'_',
IF(NEW.field3_id IS NULL, 'NULL',NEW.field3_id),'_',
IF(NEW.field4_id IS NULL, 'NULL',NEW.field4_id),'_',
IF(NEW.field5_id IS NULL, 'NULL',NEW.field5_id),'_'
)
), 1, 16), 16, 10) as unsigned integer));
END $$
DELIMITER ;