вставить несколько строк, чтобы удовлетворить ограничение

У меня две таблицы: колода (id) и карта (колода, цвет, значение)

колода имеет следующие ограничения:

  • CHECK (fifty_two_cards_deck(id))
  • PRIMARY KEY (id)

    СОЗДАТЬ ФУНКЦИЮ пятьдесят_two_cards_deck (целое число колоды) ВОЗВРАЩАЕТ логическое значение ЯЗЫК sql СТАБИЛЬНЫЙ СТРОГ КАК $ $ SELECT COUNT (*) = 52 С карты WHERE deck = $ 1 $ $;

и у карты есть эти ограничения:

  • FOREIGN KEY (deck) REFERENCES deck(id)
  • PRIMARY KEY (deck, color, value)

Как я могу вставить новую колоду?

Я пробовал это:

begin transaction;
INSERT INTO "public"."deck" ("id") VALUES (nextval('deck_id_seq'::regclass));
INSERT INTO "public"."card" ("deck", "color", "value") VALUES ('1', enum_first(null::Suit), enum_first(null::Symbol));

end transaction

(я отредактировал fifty_two_cards_deck, чтобы он был one_card_deck для целей тестирования), но я получил эту ошибку:

Ошибка SQL:

ОШИБКА: новая строка для отношения «колода» нарушает ограничение проверки «пятьдесят_two_cards_deck»

В заявлении: начать транзакцию; ВСТАВИТЬ В "public". "Deck" ("id") VALUES (nextval ('deck_id_seq' :: regclass)); ВСТАВИТЬ В "public". "Card" ("колода", "цвет", "значение") VALUES ('1', enum_first (null :: Suit), enum_first (null :: Symbol));

завершить транзакцию

Как я могу решить эту проблему, не снимая ограничений?

РЕДАКТИРОВАТЬ: решение

спасибо Магнусу Хагандеру, я заставил его работать следующим образом (после установки отложенного внешнего ключа):

begin transaction;

SET CONSTRAINTS ALL DEFERRED;

INSERT INTO "public"."deck-card" ("deck", "position", "color", "value") VALUES (1, 0, enum_first(null::suit), enum_first(null::Symbol));
INSERT INTO "public"."deck" ("id") VALUES (1);

end transaction

person Mathieu    schedule 01.03.2010    source источник


Ответы (1)


Это может сработать, если вы сделаете FOREIGN KEY с помощью DEFERRABLE, а затем установите его на DEFERRED. Затем вы вставляете в «карточную» таблицу сначала, а затем в «колоду». Проверочные ограничения выполняются во время вставки (таким образом, задолго до того, как существуют записи в «карточке»), и их нельзя отложить до завершения транзакции.

Но на самом деле это не поможет обойти тот факт, что ваше ограничение нарушено и должно быть удалено;) Это ограничение CHECK будет проверять только строки, входящие в «колоду». Но после того, как строка была вставлена ​​туда, вы все равно сможете добавлять или удалять строки из таблицы «card», и ограничение CHECK не будет жаловаться до тех пор, пока вы в следующий раз не попытаетесь изменить «колоду».

person Magnus Hagander    schedule 01.03.2010
comment
на самом деле, из-за первичного ключа на карте и того факта, что цвет и значение являются перечислениями, я не могу добавить больше карт в колоду. но я могу удалить некоторые. Я собираюсь посмотреть, могут ли триггеры решить эту проблему (например, проверить, что пятьдесят_two_cards_deck (row.deck) возвращают значение true перед удалением строки). Почему вы предлагаете удалить ограничение вместо того, чтобы исправить это? Я всегда думал, что чем больше (полезных) ограничений, тем лучше он. - person Mathieu; 01.03.2010
comment
Возможно, вы сможете исправить это с помощью триггера, но это может вызвать проблемы с параллелизмом. Причина его удаления указана в параграфе выше - вы пытаетесь использовать ограничение CHECK для чего-то, для чего оно не предназначено, и в нем есть много подводных камней - только одна из которых разрешает DELETE. - person Magnus Hagander; 02.03.2010