Использование if else для значения в одной таблице для вставки данных в другую таблицу - PullRequest
0 голосов
/ 18 сентября 2018

Я хочу разрешить пользователю добавлять данные в мою таблицу 'posts', если запись пользователя в моей таблице 'users' имеет значение banned_till либо nil, либо меньше текущего времени.

Что-то вроде (псевдокод);

If (select banned_till from users where userid = $1) = nil or < currentTime
   Insert in posts (col1, col2) values ('abc', 'xyz')
ELSE
   RAISE Exception "User is banned"
ENDIF

В настоящее время я делаю это с помощью 2 запросов;первый проверяет, забанен ли пользователь, а второй вставляет в таблицу сообщений.Я бы действительно хотел объединить их в один запрос, если смогу.

Примечание: я бы действительно предпочел не использовать и хранить процедуры или что-то слишком специфичное для БД SQL.Что-то простое и универсальное гораздо предпочтительнее.


РЕДАКТИРОВАТЬ: я пошел с измененной версией ответа Эрвина.

DO
$$
BEGIN
    IF (select banned_till from users where unqid = 'user01') < now() THEN
      RAISE EXCEPTION 'User is banned';
    ELSE
        insert into posts (unqid, title, link, content, author_id, author_nick, author_flair) 
            SELECT 'pid03', 'Sample post title', 'www.google.com', 'This is a sample Post Content', unqid, nickname, flair 
            from users where unqid = 'user01';
    END IF;
END
$$;

Плюсы: Теперь моя проверка бана происходит до того, как другие запросы дажеуволена.Нет гоночных условий.Самое главное, теперь у меня могут быть два разных сообщения об ошибках - одно для проверки бана, а другое для unqid не совпадает.Минусы: я дважды повторяю запрос на выборку для пользователей

Ответы [ 2 ]

0 голосов
/ 18 сентября 2018

В Postgres вы можете выразить это как один запрос:

with s as (
      select banned_till
      from users where userid = $1
     ),
     i as (
      insert into posts (col1, col2)
          select v.col1, v.col2
          from (values ('abc', 'xyz')) v(col1, col2)
          where (select coalesce(max(banned_till), current_date) from s) < now()
    )
select max( coalesce(max(banned_till), current_date) ) < current_time as is_success
from s;
0 голосов
/ 18 сентября 2018

Не запускайте отдельную SELECT, это просто добавило бы стоимость - и вводите условие беспричинной гонки при одновременной загрузке записи: пользователь может быть забанен между SELECT и INSERT или аналогичными осложнениями.

Быстрее, проще и безопаснее в условиях гонки:

INSERT INTO posts (col1, col2) 
SELECT 'abc', 'xyz'
FROM   users
WHERE  userid = $1  -- assuming userid is UNIQUE
AND   (banned_till >= currentTime) IS NOT TRUE;

Если вам нужно исключение, вы можете заключить его в функцию или оператор SQL DO:

DO
$$
BEGIN
   INSERT INTO posts (col1, col2)
   SELECT 'abc', 'xyz'
   FROM   users
   WHERE  userid = $1
   AND   (banned_till >= currentTime) IS NOT TRUE;

   IF NOT FOUND THEN
      RAISE EXCEPTION 'User is banned';
   END IF;
END
$$;

О IF NOT FOUND:

Состояние гонки может быть неуместным (как в вашем случае, вероятно) или разрушительным, в зависимости отваши точные требования.Связанные:

...