Ecto - 创建一个约束,其中只有一列不为空
Ecto - Creating a constraint where only one column is not null
我的 table 中有两组列:
A = ['column_a', 'column_b', 'column_c']
B = ['column_d', 'column_e', 'column_f']
我需要在满足这些条件的地方创建约束:
- A 中的 1 列不为空,B 中的 1 列不为空。
- A 中正好有 1 列不为空且与 B 相同。
- A 和 B 中的这对列对于每条记录都必须是唯一的。
到目前为止,我已经创建了一个约束来检查每个集合中至少有一个列不为空,但我不知道如何从这里开始:
create(constraint(:table, :valid_pair, check: "COALESCE(column_a, column_b, column_c) IS NOT NULL AND COALESCE(column_d, column_e, column_f) IS NOT NULL"))
此外,如何在我的变更集中实施此约束?
约束条件
如本 SO question 所示,要满足约束 1 和 2,您可以使用类似的东西:
create constraint(:table, :valid_pair, check: "
(
( CASE WHEN column_a IS NULL THEN 0 ELSE 1 END
+ CASE WHEN column_b IS NULL THEN 0 ELSE 1 END
+ CASE WHEN column_c IS NULL THEN 0 ELSE 1 END
+ CASE WHEN column_d IS NULL THEN 0 ELSE 3 END
+ CASE WHEN column_e IS NULL THEN 0 ELSE 3 END
+ CASE WHEN column_f IS NULL THEN 0 ELSE 3 END
) = 4
)")
约束 3 有一些歧义,你是说 column_a
和 column_f
绝对只能在一起一次,还是它们的值的配对必须是唯一的?
对于[column_a, column_b, column_c, column_d, column_e, column_f]
:
这些交易都是有效的还是只有一个?
[1, NULL, NULL, NULL, NULL, NULL, 1]
[1, NULL, NULL, NULL, NULL, NULL, 2]
如果是后者,则:
create unique_index(:table, [:column_a, :column_b, :column_c, :column_d, :column_e, :column_f], name: :unique_pairing)
变更集
对于约束 1 和 2,我将执行两个自定义验证,计算每个列子集中非零值的数量。这些验证是在访问数据库之前完成的。写得好:More Custom Validations for Ecto Changesets
changeset
...
|> validate_column_sets([column_a, column_b, column_c], :column_set_a)
|> validate_column_sets([column_d, column_e, column_f], :column_set_b)
defp validate_column_sets(changeset, fields, key) do
case changeset.valid? do
true ->
case Enum.count(fields, fn field -> get_field(changeset, field) != nil end) do
1 -> changeset
_ -> add_error(changeset, key, "Only one column in this set can be nil")
_ ->
changeset
end
end
对于约束 3,您可以保持简单并使用 unique_constraint/3
和任意列。
在此处查看讨论:Ecto Changeset unique_constraint/3
for clustered index
|> unique_constraint(:column_a, name: :letters_unique_index)
希望这能让你走上正轨!
我的 table 中有两组列:
A = ['column_a', 'column_b', 'column_c']
B = ['column_d', 'column_e', 'column_f']
我需要在满足这些条件的地方创建约束:
- A 中的 1 列不为空,B 中的 1 列不为空。
- A 中正好有 1 列不为空且与 B 相同。
- A 和 B 中的这对列对于每条记录都必须是唯一的。
到目前为止,我已经创建了一个约束来检查每个集合中至少有一个列不为空,但我不知道如何从这里开始:
create(constraint(:table, :valid_pair, check: "COALESCE(column_a, column_b, column_c) IS NOT NULL AND COALESCE(column_d, column_e, column_f) IS NOT NULL"))
此外,如何在我的变更集中实施此约束?
约束条件
如本 SO question 所示,要满足约束 1 和 2,您可以使用类似的东西:
create constraint(:table, :valid_pair, check: "
(
( CASE WHEN column_a IS NULL THEN 0 ELSE 1 END
+ CASE WHEN column_b IS NULL THEN 0 ELSE 1 END
+ CASE WHEN column_c IS NULL THEN 0 ELSE 1 END
+ CASE WHEN column_d IS NULL THEN 0 ELSE 3 END
+ CASE WHEN column_e IS NULL THEN 0 ELSE 3 END
+ CASE WHEN column_f IS NULL THEN 0 ELSE 3 END
) = 4
)")
约束 3 有一些歧义,你是说 column_a
和 column_f
绝对只能在一起一次,还是它们的值的配对必须是唯一的?
对于[column_a, column_b, column_c, column_d, column_e, column_f]
:
这些交易都是有效的还是只有一个?
[1, NULL, NULL, NULL, NULL, NULL, 1]
[1, NULL, NULL, NULL, NULL, NULL, 2]
如果是后者,则:
create unique_index(:table, [:column_a, :column_b, :column_c, :column_d, :column_e, :column_f], name: :unique_pairing)
变更集
对于约束 1 和 2,我将执行两个自定义验证,计算每个列子集中非零值的数量。这些验证是在访问数据库之前完成的。写得好:More Custom Validations for Ecto Changesets
changeset
...
|> validate_column_sets([column_a, column_b, column_c], :column_set_a)
|> validate_column_sets([column_d, column_e, column_f], :column_set_b)
defp validate_column_sets(changeset, fields, key) do
case changeset.valid? do
true ->
case Enum.count(fields, fn field -> get_field(changeset, field) != nil end) do
1 -> changeset
_ -> add_error(changeset, key, "Only one column in this set can be nil")
_ ->
changeset
end
end
对于约束 3,您可以保持简单并使用 unique_constraint/3
和任意列。
在此处查看讨论:Ecto Changeset unique_constraint/3
for clustered index
|> unique_constraint(:column_a, name: :letters_unique_index)
希望这能让你走上正轨!