Я использую базу данных postgres, и моя проблема включает в себя две таблицы, упрощенные версии которых приведены ниже.PostgreSQL INSERT с операторами
CREATE TABLE events(
id SERIAL PRIMARY KEY NOT NULL,
max_persons INTEGER NOT NULL
);
и
CREATE TABLE requests(
id SERIAL PRIMARY KEY NOT NULL,
confirmed BOOLEAN NOT NULL,
creation_time TIMESTAMP DEFAULT NOW(),
event_id INTEGER NOT NULL /*foreign key*/
);
Есть n
событий и каждое событие может иметь до events.max_persons
участников. Новые запросы должны быть подтверждены и действительны до 30 минут. После этого периода запросы будут проигнорированы, если они не были подтверждены.
Теперь , что я хочу сделать только вставить новый request
, когда сумма всех подтвержденных запросов и все запросы, которые остаются в силе, но не подтверждено, меньше events.max_persons
.
У меня уже есть запрос на выбор одного события. Вот упрощенная версия этого, просто чтобы дать вам представление о том, как она должна работать
SELECT
e.id,
SUM(CASE WHEN r.confirmed = 1 THEN 1 ELSE 0 END) AS number_confirmed
SUM(CASE WHEN r.creation_time > (CURRENT_TIMESTAMP - INTERVAL '30 MINUTE') AND r.confirmed = 0 THEN 1 ELSE 0 END) AS number_reserved,
e.max_persons
FROM events e, requests r
WHERE l.id = ?
AND r.event_id = e.id
AND (r.confirmed = 1 OR r.creation_time > (CURRENT_TIMESTAMP - INTERVAL '30 MINUTE'))
GROUP BY e.id, e.max_persons
HAVING SUM(CASE WHEN r.confirmed = 1 OR (r.creation_time > (CURRENT_TIMESTAMP - INTERVAL '30 MINUTE')) THEN 1 ELSE 0 END) < e.max_persons";
ли possibile добиться этого с помощью одного INSERT - команды?
Здравствуйте, извините за поздний ответ. В настоящее время я решил свою проблему, выполнив запрос, который получает разницу между max_persons и number_booked/number_reserved и выполняет только оператор insert, если он больше 0. Является ли это жизнеспособной практикой? И еще один вопрос, если я использую транзакции SERIALIZABLE, я в порядке с проблемами, например, когда два человека пытаются зарегистрироваться для одного и того же события одновременно, но остается только одно место? – PrototypeX7
Ваша текущая техника уязвима для проблемы, которую я указал в своем ответе --- если две такие транзакции выполняются параллельно, и только одно место бесплатное, они оба добавят новый запрос. С SERIALIZABLE это не могло случиться. Одна из транзакций будет прекращена с ошибкой сериализации и должна быть повторена. Во время повторной попытки было показано, что мероприятие уже забронировано. –
Спасибо, собираюсь попробовать это! – PrototypeX7