Нет необходимости в PL / pgSQL или цикле.Вы можете использовать список тегов и проверять существование каждого из них в одном выражении:
with to_check (itag) as (
values ('nature'),('science'),('funny'),('politics'),('news')
)
select tc.itag,
exists (select * from tags t where t.name = tc.itag) as tag_exists
from to_check tc;
Если вы просто хотите, чтобы один флаг сообщал вам, если хотя бы один тег отсутствует, выможно использовать следующее:
with to_check (itag) as (
values ('nature'),('science'),('funny'),('politics'),('news')
)
select bool_and(exists (select * from tags t where t.name = tc.itag)) as all_tags_present
from to_check tc;
bool_and
вернет true только если все значения верны.
Вы получаете ошибку, потому что {'nature', 'politics'}
является недопустимым литералом массива.Вам нужно либо использовать конструктор array
array['nature', 'politics']
, либо строковый литерал, который можно привести к массиву
'{nature, politics}'::text[]
(обратите внимание, что фигурные скобки внутри строки).
Я предпочитаю конструктор массива, так как мне не нужно беспокоиться о вложенности строковых литералов.
Идея состоит в том, что пользователь не может добавить новый тег, которыйотсутствует в системе
Правильное решение этой проблемы состоит в том, чтобы иметь одну таблицу, содержащую определения тегов и обеспечивающую использование каждого имени тега только один раз:
create table tag_definition
(
name varchar(50) primary key
);
Затем в вашей таблице тегов укажите тег_определения:
create table tags
(
name varchar(50) not null references tag_definition,
post_id integer not null references posts
);
Теперь невозможно вставить несуществующий тег в таблицу tags
.
Все, что вам нужно сделать сейчас, это перехватить исключение при вставке строк.Нет необходимости проверять теги перед вставкой .
Вы можете сэкономить место и существенно уменьшить таблицу tags
, используя сгенерированный первичный ключ для таблицы tag_definition
(например,serial
) и используйте это для справки в таблице tags
.
Учитывая оператор вставки в вашем вопросе, вы могли бы добиться того же с помощью одного оператора вставки:
with to_check (itag) as (
values ('nature'),('politics')
)
insert into tags (tag, post_id)
select tc.itag, 'post01'
from to_check tc
where not exists (select itag
from to_check
except
select t.name
from tags t);
Однако это не очень хорошо масштабируется при увеличении таблицы тегов,Подвыбор ничего не вернет, если все теги из to_check
существуют, и, следовательно, условие not exists
заставит INSERT вернуть все.Если хотя бы один тег не существует, ничего не будет вставлено.
Чтобы сделать это (несколько) эффективным, вам понадобится индекс `тэгов (имя).