Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/74.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 使用空值创建复合唯一索引的首选方法_Mysql_Sql_Indexing - Fatal编程技术网

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 ;