【问题标题】:Ecto - Creating a constraint where only one column is not nullEcto - 创建一个只有一列不为空的约束
【发布时间】:2020-03-11 08:39:14
【问题描述】:

我的表中有两组列:

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】:

    约束

    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,我将执行两个自定义验证,计算每个列子集中的非零值的数量。这些验证是在访问数据库之前完成的。写得好: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)

    希望这能让你走上正轨!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-14
      • 1970-01-01
      • 1970-01-01
      • 2010-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-10
      相关资源
      最近更新 更多