Необходимо реализовать ограничение записей в таблицу за текущую дату. Postgres
Есть таблица в бд
CREATE TABLE fio (
id serial,
user_id BIGINT NOT NULL PRIMARY KEY,
first_name TEXT NOT NULL,
second_name TEXT NOT NULL,
age INT NOT NULL,
date_in date DEFAULT CURRENT_DATE);
Заполняется таблица из бота в телеграме.
Запрос на заполнение - (
"INSERT INTO fio(user_id, first_name, second_name, age) VALUES (%s,%s,%s,%s)",
(chat_id, first_name, second_name, age))
То есть, бот собирает данные о пользователях, для регистрации.
Нужно реализовать ограничение на заполнение 100 пользователей в текущую дату, если число превышено, в бот должен вернуться ответ - "ошибка".
Подскажите, как это лучше сделать, подзапросом или с помощью триггера?
Необходимо самое простое решение. Большое спасибо!
UPD: Запрос найти удалось. Помогите вернуть ошибку, если запись не добавилась, надо как-то получить от БД ответ, что запись не прошла.
Запрос -
("INSERT INTO fio (user_id, first_name, second_name, age)
SELECT %s,%s,%s,%s WHERE EXISTS (SELECT COUNT(1) FROM fio
WHERE date_in = CURRENT_DATE HAVING COUNT(1) < 5);",
(chat_id, first_name, second_name, age)
Ответы (3 шт):
Силами базы данных это просто не сделать. Вероятней всего даже вообще не сделать - без каких-то особых извращений.
Проще перед добавлением записи проверять число записей за текущую дату
SELECT COUNT(*) FROM fio WHERE date_in = now()::date
и уже получив количество принимать решение - добавлять новую запись или возвращать ошибку
Задача решается созданием пользовательской функции, которая используется в табличном CHECK CONSTRAINT.
DEMO
CREATE TABLE fio (
id serial,
user_id BIGINT NOT NULL PRIMARY KEY,
first_name TEXT NOT NULL,
second_name TEXT NOT NULL,
age INT NOT NULL,
date_in date DEFAULT CURRENT_DATE);
CREATE FUNCTION amount_today(OUT amount INT)
AS $$
SELECT COUNT(*) FROM fio WHERE date_in = CURRENT_DATE
$$ LANGUAGE SQL;
ALTER TABLE fio ADD CHECK (amount_today() < 3);
INSERT INTO fio(user_id, first_name, second_name, age) VALUES (1, 'Иван', 'Иванов', 30);
INSERT INTO fio(user_id, first_name, second_name, age) VALUES (8, 'Пётр', 'Петров', 40);
INSERT INTO fio(user_id, first_name, second_name, age) VALUES (23, 'Сидор', 'Сидоров', 25);
INSERT INTO fio(user_id, first_name, second_name, age) VALUES (41, 'Василий', 'Пупкин', 33);
ERROR: new row for relation "fio" violates check constraint "fio_check" DETAIL: Failing row contains (4, 41, Василий, Пупкин, 33, 2023-03-29).
SELECT * FROM fio;
| id | user_id | first_name | second_name | age | date_in |
|---|---|---|---|---|---|
| 1 | 1 | Иван | Иванов | 30 | 2023-03-29 |
| 2 | 8 | Пётр | Петров | 40 | 2023-03-29 |
| 3 | 23 | Сидор | Сидоров | 25 | 2023-03-29 |
Просится триггер на вставку данных, но:
- Вообще-то кажется, что задача какая-то неправильная - прибивать в БД ограничение на число записей на текущую дату.
- Не оставляет ощущение, что остается лазейка вставки большего числа записей задним числом (за вчера и т.п.)
- Вообще мне кажется ответ @Akina с констрейном лучше
Ну да ладно, тоже вариант:
CREATE FUNCTION check_today_count() RETURNS trigger AS $check_today_count$
DECLARE
today_exists integer;
BEGIN
-- Получить число записей за текущую дату
today_exists = count(id) FROM fio WHERE date_in = CURRENT_DATE;
-- Выбросить исключение с ошибкой при превышении 100 записей
IF today_exists >= 100 THEN
RAISE EXCEPTION 'Error: records limit reached';
END IF;
RETURN NEW;
END;
$check_today_count$ LANGUAGE plpgsql;
CREATE TRIGGER check_today_count BEFORE INSERT ON fio
FOR EACH ROW EXECUTE PROCEDURE check_today_count();