Ecto - Создание ограничения, в котором только один столбец не равен NULL - PullRequest
0 голосов
/ 10 марта 2020

У меня есть два набора столбцов в моей таблице:

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

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

Мне нужно создать ограничение при выполнении этих условий:

  1. 1 столбец из A не является нулевым, а 1 столбец из B не является нулевым.
  2. Точно 1 столбец из A не является нулевым и одинаковым для 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"))

Кроме того, как мне реализовать это ограничение в моем наборе изменений?

1 Ответ

0 голосов
/ 11 марта 2020

Ограничения

Как показано в этом вопросе SO , для удовлетворения ограничений 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)

Changesets

Для ограничений 1 и 2 я бы сделал две пользовательские проверки, которые подсчитывают количество ненулевых значений из каждого подмножества столбцов. Эти проверки выполняются до попадания в базу данных. Хорошая запись: Больше пользовательских проверок для 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 для кластерного индекса

|> unique_constraint(:column_a, name: :letters_unique_index)

Надеюсь, что вы попадете на правильный путь!

...