两列之一为空时的唯一索引
Unique index when one of two columns is null
(Rails 4.2.1, Sqlite3) 我有三个模型——M1、M2、M3。
M1belongs_toM2
M1 也belongs_toM3
M1 有一个 :name(字符串)字段。
我有以下必须验证的限制条件:
1) M1 记录可以关联 M2 或 M3,但不能同时关联两者。
2) M1名称必须在指定的M2或M3中是唯一的。
我已经在模型中实现了约束条件 (1),它按预期工作。 (我提到它只是因为它可能与场景有关)。
对于约束(2),我在迁移中添加了一个索引如下:
add_index :m1s, [:name, :m2_id, :m3_id], unique: true, name: "idx_m1_name"
然后我打电话给:
> m2 = M2.create! # success
> m1_1 = M1.create!(name: 'm1_1', m2: m2) #success
> m1_2 = M1.create!(name: 'm1_1', m2: m2) # this line should fail, but doesn't
m1_1 和 m1_2 被创建 - 我预计 m1_2 应该由于唯一性约束而失败。
我检查了索引是否按预期添加。此外,根据约束 1,m3_id 在 m1_1 和 m1_2 中均为 nil,不确定是否相关。
为什么约束没有被检查?
所以在这两种情况下 m3_id
都是 NULL
?在 Sqlite3 中,空值被认为与唯一索引上下文中的另一个空值不同。
For the purposes of unique indices, all NULL values are considered to
different from all other NULL values and are thus unique
见https://sqlite.org/lang_createindex.html
我认为 MySQL 和 Postgres 也一样。
你可以用两个索引来表示。
add_index :m1s, [:name, :m2_id], unique: true
add_index :m1s, [:name, :m3_id], unique: true
由于出于唯一性目的,空值被认为是不同的,因此第一个索引不会限制仅设置了 m3_id
的行,第二个索引反之亦然。
(您可能也对 CHECK
constraint that checks that exactly one of m2_id
or m3_id
is null. In Rails, CHECK
constraints have the minor caveat of requiring the schema file to be expressed in SQL. For a more general solution to "indices that only apply to some rows", see partial indices 感兴趣。)
(Rails 4.2.1, Sqlite3) 我有三个模型——M1、M2、M3。
M1belongs_toM2
M1 也belongs_toM3
M1 有一个 :name(字符串)字段。
我有以下必须验证的限制条件:
1) M1 记录可以关联 M2 或 M3,但不能同时关联两者。
2) M1名称必须在指定的M2或M3中是唯一的。
我已经在模型中实现了约束条件 (1),它按预期工作。 (我提到它只是因为它可能与场景有关)。
对于约束(2),我在迁移中添加了一个索引如下:
add_index :m1s, [:name, :m2_id, :m3_id], unique: true, name: "idx_m1_name"
然后我打电话给:
> m2 = M2.create! # success
> m1_1 = M1.create!(name: 'm1_1', m2: m2) #success
> m1_2 = M1.create!(name: 'm1_1', m2: m2) # this line should fail, but doesn't
m1_1 和 m1_2 被创建 - 我预计 m1_2 应该由于唯一性约束而失败。
我检查了索引是否按预期添加。此外,根据约束 1,m3_id 在 m1_1 和 m1_2 中均为 nil,不确定是否相关。
为什么约束没有被检查?
所以在这两种情况下 m3_id
都是 NULL
?在 Sqlite3 中,空值被认为与唯一索引上下文中的另一个空值不同。
For the purposes of unique indices, all NULL values are considered to different from all other NULL values and are thus unique
见https://sqlite.org/lang_createindex.html
我认为 MySQL 和 Postgres 也一样。
你可以用两个索引来表示。
add_index :m1s, [:name, :m2_id], unique: true
add_index :m1s, [:name, :m3_id], unique: true
由于出于唯一性目的,空值被认为是不同的,因此第一个索引不会限制仅设置了 m3_id
的行,第二个索引反之亦然。
(您可能也对 CHECK
constraint that checks that exactly one of m2_id
or m3_id
is null. In Rails, CHECK
constraints have the minor caveat of requiring the schema file to be expressed in SQL. For a more general solution to "indices that only apply to some rows", see partial indices 感兴趣。)