如何创建一个唯一的索引,只有某些值需要是唯一的?

Zab*_*bba 3 mysql unique-constraint

我有一个存储在表中的代码列表,有些代码应该是唯一的,其他代码可以重复。这些代码应该是唯一范围到另一个字段product_id.

假设每个代码11只允许一次product_id,并且允许其他代码重复,该表将如下所示:

product_id     code
1              11   # Needs to be unique for product_id 1
1              222
1              222
1              333
2              11   # Needs to be unique for product_id 2
2              222
2              444
Run Code Online (Sandbox Code Playgroud)

使用 MySQL,我利用了一个事实,即您可以在唯一索引中拥有多个 NULL 值,因此通过添加一个“决胜局”(?) 字段ucode,我能够一起破解一个解决方案:

product_id  code   ucode
1           11     1    # Code 11 needed to be unique, so 1 for ucode
1           222    NULL # Code 222 can be repeated, so NULL for ucode
1           222    NULL
1           333    NULL
2           11     1
2           222    NULL
2           444    NULL
Run Code Online (Sandbox Code Playgroud)

然后在 [product_id, code, ucode] 上建立唯一索引。对于唯一代码,该ucode字段设置为1,否则设置为NULL

这有效,但感觉非常笨拙。有没有更好的方法可以做到这一点?

(我正在使用 MySQL)

ype*_*eᵀᴹ 8

MySQL 5.7MariaDB 5.2+版本中,您可以使用(生成的)VIRTUAL列来完成此操作。您定义ucode为虚拟列,然后添加UNIQUE约束:

CREATE TABLE codes 
  ( product_id  INT NOT NULL,
    code INT NOT NULL,
    ucode BIT AS (CASE WHEN code  = 11 THEN b'1' ELSE NULL END) 
        VIRTUAL,
        -- PERSISTENT,    -- for persistent storage of the value in MariaDB
        -- STORED,        -- for persistent storage of the value in MySQL 
    CONSTRAINT code_11_product_id_unique
        UNIQUE (ucode, product_id)
  ) ;
Run Code Online (Sandbox Code Playgroud)

在 dbfiddle.uk 测试

insert into codes
  (product_id, code)
values 
  (1, 11),
  (1, 222),
  (1, 222),
  (1, 333),
  (2, 11),
  (2, 222),
  (2, 222);
Run Code Online (Sandbox Code Playgroud)
?
select * from codes;
Run Code Online (Sandbox Code Playgroud)
product_id | 代码 | 代码
---------: | ---: | :----
         1 | 11 | 1    
         1 | 第222话  
         1 | 第222话  
         1 | 第333话 空值 
         2 | 11 | 1    
         2 | 第222话  
         2 | 第222话 空值 
insert into codes          -- should fail
  (product_id, code)
values 
  (2, 11) ;
Run Code Online (Sandbox Code Playgroud)
密钥“code_11_product_id_unique”的重复条目“\x01-2”
select * from codes;
Run Code Online (Sandbox Code Playgroud)
product_id | 代码 | 代码
---------: | ---: | :----
         1 | 11 | 1    
         1 | 第222话  
         1 | 第222话  
         1 | 第333话 空值 
         2 | 11 | 1    
         2 | 第222话  
         2 | 第222话 空值 

  • 天哪,这应该是几十个“具有 NULL 值的复合唯一键”搜索的公认答案。太感谢了! (2认同)