У меня есть колонка: standard BOOLEAN NOT NULL
Я хотел бы обеспечить один ряд True, а все остальные False. Это не FK или что-либо еще в зависимости от этого ограничения. Я знаю, что могу сделать это с помощью plpgsql, но это похоже на кувалду. Я предпочел бы что - то вроде CHECK
или UNIQUE
ограничения. Чем проще, тем лучше.
Одна строка должна быть True, они не могут быть ложными (поэтому первая вставленная строка должна быть True).
Строка должна быть обновлена, что означает, что мне нужно ждать, чтобы проверить ограничения, пока не будут выполнены обновления, поскольку все строки могут быть установлены в False в первую очередь, а одна строка в True после.
Существует FK между products.tax_rate_id
и tax_rate.id
, но это не имеет ничего общего с неисполнением или стандартной ставки налога, который выбирается пользователем , чтобы облегчить создание новых продуктов ..
PostgreSQL 9.5, если это имеет значение.
Фон
В таблице указана ставка налога. По умолчанию standard
используется одна из налоговых ставок ( поскольку по умолчанию используется команда Postgres). При добавлении нового продукта к нему применяется стандартная налоговая ставка. Если нет standard
, база данных должна либо сделать предположение, либо выполнить все виды ненужных проверок. Я подумал, что простым решением было убедиться, что оно есть standard
.
Под «по умолчанию» выше я подразумеваю уровень представления (UI). Существует пользовательская опция для изменения ставки налога по умолчанию. Мне нужно либо добавить дополнительные проверки, чтобы гарантировать, что GUI / пользователь не пытается установить tax_rate_id в NULL, либо просто установить ставку налога по умолчанию.
Ответы:
Вариант 1
Поскольку все, что вам нужно, это один столбец с
standard = true
, установите стандартное значение NULL во всех других строках. Тогда работает простоеUNIQUE
ограничение, поскольку значения NULL не нарушают его:DEFAULT
является необязательным напоминанием, что первая введенная строка должна стать значением по умолчанию. Это ничего не навязывает . Хотя вы не можете установить более одной строкиstandard = true
, вы все равно можете установить все строки NULL. Нет четкого способа предотвратить это, используя только ограничения в одной таблице.CHECK
ограничения не учитывают другие строки (без подвохов).Связанные с:
Ограничить два конкретных значения столбца из существующих одновременно
Добавьте ограничение, чтобы сделать столбец уникальным для каждой группы строк.
Обновить:
Чтобы разрешить команду типа (где ограничение выполняется только в конце оператора):
..
UNIQUE
ограничение должно бытьDEFERRABLE
. Видеть:dbfiddle здесь
Вариант 2
Есть вторая таблица с одной строкой, как:
Создайте это как суперпользователь:
Теперь всегда есть одна строка, указывающая на стандарт (в этом простом случае, также представляющая стандартную ставку напрямую). Только суперпользователь может сломать его. Вы также можете запретить это с помощью триггера
BEFORE DELETE
.dbfiddle здесь
Связанные с:
Вы можете добавить,
VIEW
чтобы увидеть то же самое, что и в варианте 1 :В запросах, где все, что вам нужно, это стандартная ставка, используйте (только)
taxrate_standard.taxrate
напрямую.Вы позже добавили:
А реализация бедняка варианта 2 будет просто добавить строку в
products
(или любую аналогичную таблицу) , указывающую на стандартные ставки налога; фиктивный продукт, который вы могли бы назвать «Стандартная налоговая ставка» - если ваша настройка позволяет это.Ограничения FK обеспечивают ссылочную целостность. Чтобы завершить это, примените
tax_rate_id IS NOT NULL
для строки (если это не относится к столбцу в целом). И запретить его удаление. Оба могут быть включены в триггеры. Никакого дополнительного стола, но менее элегантный и не такой надежный.источник
CROSS JOIN
противостоять стандарту,LEFT JOIN
конкретному, а затемCOALESCE
между ними.CONSTRAINT standard_only_1_true UNIQUE (standard)
: я предполагаю, что таблица не будет большой, так что это не имеет большого значения, но поскольку ограничение будет определять индекс для всей таблицы, разве частичный уникальный индекс не будетWHERE (standard)
использовать меньше места?Вы можете использовать фильтрованный индекс
dbfiddle здесь
Но, как вы сказали, первая строка должна быть истинной, тогда вы можете использовать ограничение CHECK, но даже используя функцию, вы можете удалить первую строку позже.
dbfiddle здесь
Вы можете решить эту проблему, добавив триггер BEFORE DELETE, чтобы убедиться, что первая строка (foo is true) никогда не удаляется.
dbfiddle здесь
источник