Ecto-创建一个约束,其中只有一列不为空

问题描述 投票:0回答:1

我的表中有两组列:

A = ['column_a', 'column_b', 'column_c']

B = ['column_d', 'column_e', 'column_f']

我需要在满足这些条件的地方创建约束:

  1. A中的1列不为空,B中的1列也不为空。
  2. 来自A的确切1列不为空,并且与B相同。
  3. 对于每个记录,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"))

此外,如何在我的变更集中实施此约束?

postgresql elixir ecto
1个回答
0
投票

约束

如此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_acolumn_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,我将执行两个自定义验证,这些验证将对来自每个列子集的非nil值的数量进行计数。这些验证是在命中数据库之前完成的。写得好: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/3

希望您能走上正确的轨道!

© www.soinside.com 2019 - 2024. All rights reserved.