Какая строка нарушает это проверочное ограничение?

Я пытаюсь добавить следующее ограничение проверки в таблицу raffle_participant:

ALTER TABLE raffle_participant ADD CONSTRAINT ck_raffle_participant_total_purchased_le_ticket_limit CHECK (tickets_purchased_in_raffle(raffle_id) <= get_ticket_limit(raffle_id))

Когда я выполняю указанную выше команду, я возвращаюсь:

ERROR:  check constraint "ck_raffle_participant_total_purchased_le_ticket_limit" of relation "raffle_participant" is violated by some row

Мне кажется, что все строки в таблице raffle_participant удовлетворяют ограничению. Что я тут не понимаю? Почему ограничение проверки нарушается для существующих данных?

Использование PostgreSQL версии 13.6.

Редактировать: Я пробовал следующие запросы, чтобы выяснить, какие строки нарушают ограничение, и, похоже, ни один из них не делает этого.

development=# select (select sum(p.tickets_purchased) from raffle_participant p where p.raffle_id = 2) <= (select r.ticket_limit from raffle r where r.id = 2);
 ?column? 
----------
 t
(1 row)

development=# select (select sum(p.tickets_purchased) from raffle_participant p where p.raffle_id = 3) <= (select r.ticket_limit from raffle r where r.id = 3);
 ?column? 
----------
 t
(1 row)

development=# select (select sum(p.tickets_purchased) from raffle_participant p where p.raffle_id = 4) <= (select r.ticket_limit from raffle r where r.id = 4);
 ?column? 
----------
 t
(1 row)

лотерейный стол

Схема

СтолбецТипСопоставлениеОбнуляемыйПо умолчанию
я быцелое числоненулевойгенерируется всегда как личность
название предметапеременный характер(40)ненулевой
item_valueбольшойинтненулевой
ticket_limitцелое числоненулевой
Стоимость билетабольшойинтненулевой
user_ticket_limitцелое числоненулевой
закончилось_навременная метка с часовым поясом
id_победителябольшойинт

Данные

я быназвание предметаitem_valueticket_limitСтоимость билетаuser_ticket_limitзакончилось_наid_победителя
1вещь10101022022-04-27 17:46:01.271025+00
2вещь101010102022-04-27 17:55:28.783744+00151150118697959424
3вещь101010102022-04-27 20:32:13.588843+00151150118697959424
4вещь10101010

стол raffle_participant

Схема

СтолбецТипСопоставлениеОбнуляемыйПо умолчанию
raffle_idцелое числоненулевой
Логин пользователябольшойинтненулевой
ticket_purchasedцелое числоненулевой

Данные

raffle_idЛогин пользователяticket_purchased
215115011869795942410
315115011869795942410
41511501186979594243

функция ticket_purchased_in_raffle

CREATE FUNCTION tickets_purchased_in_raffle (IN raffle_id raffle.id%TYPE) 
  RETURNS raffle_participant.tickets_purchased%TYPE AS
  $$ 
    SELECT SUM(p.tickets_purchased) FROM raffle_participant p WHERE p.raffle_id = raffle_id 
  $$
LANGUAGE SQL

функция get_ticket_limit

CREATE FUNCTION get_ticket_limit (IN raffle_id raffle.id%TYPE) 
  RETURNS raffle.ticket_limit%TYPE AS
  $$
    SELECT r.ticket_limit FROM raffle r WHERE r.id = raffle_id 
  $$
LANGUAGE SQL

вот что не удалось: (tickets_purchased_in_raffle(raffle_id) <= get_ticket_limit(raffle_id))

Daniel A. White 08.05.2022 00:14

Что ты имеешь в виду? Является ли синтаксис этого контрольного ограничения недопустимым? Моя проблема в том, что я не могу добавить ограничение в таблицу с показанными данными. Глядя на данные, кажется, что нет нарушающих строк.

jcarrete5 08.05.2022 00:20

нет, когда postgres пытается добавить ограничение, он проверяет все строки, и у вас есть некоторые, которые нарушают это, поэтому есть по крайней мере одна строка, которая имеет (tickets_purchased_in_raffle(raffle_id) > get_ticket_limit(raffle_id)), поэтому сделайте SELECT и выберите это первый

nbk 08.05.2022 00:24

К вашему сведению, то, что вы делаете, не является хорошей идеей. Отсюда Создать таблицу: "В настоящее время выражения CHECK не могут содержать подзапросы и ссылаться на переменные, отличные от столбцов текущей строки...". Обман с помощью функции — не способ обойти это. В CHECK нет отслеживания зависимостей, поэтому вполне возможно, что при переносе этого в новую базу данных произойдет сбой, потому что CHECK запускается до того, как будут загружены необходимые ему функции. Для такого рода вещей используйте триггер.

Adrian Klaver 08.05.2022 00:34

Я заметил, что вы не проверили raffle_id = 1. Лучше принять ошибку за истину и найти исключение из правила, которое приводит к сбою CHECK. Также помните sum(), где raffle_id не существует, это NULL, а NULL <= <some_number> будет NULL, а не «t» или «f».

Adrian Klaver 08.05.2022 00:46
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
0
5
41
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема в том, что мой входной аргумент raffle_id для tickets_purchased_in_raffle затенялся именем столбца raffle_id из raffle_participant. Изменив имя аргумента на rid, я смог успешно добавить контрольное ограничение.

Повторяю свое предупреждение, не делайте этого. Использование функции и/или обращение к строкам в другой таблице вызовет у вас проблемы. Для более подробного объяснения см. Проверить ограничения, в частности часть Примечание.

Adrian Klaver 08.05.2022 00:50

Отмеченный. Я рассмотрю возможность использования триггеров для этого. Спасибо

jcarrete5 08.05.2022 00:55

Другие вопросы по теме