I'd like to create a function that returns items
based on their tags
. However, I do not know how to format an array in the IN()
clause. I believe that is why I get no result.
Here is what I got:
CREATE OR REPLACE FUNCTION getItemsByTag(tags text[])
RETURNS TABLE (id bigint, title text, tag text[]) AS $$
BEGIN
IF array_length(tags, 1) > 0
THEN
EXECUTE format('
SELECT d.id, d.title, array_agg(t.title)
FROM items d
INNER JOIN item_tags dt
ON dt.item_id = d.id
INNER JOIN tags t
ON t.id = dt.tag_id
AND t.title IN (%L)
GROUP BY d.id, d.title
', array_to_string(tags, ','));
-- ELSE ...
END IF;
END;
$$ LANGUAGE plpgsql;
Then when I call:
select getItemsByTag('{"gaming", "sport"}');
I get no result even though there are items tagged with "gaming".
Test case
CREATE TABLE items(
id serial primary key,
title text);
CREATE TABLE tags(
id serial primary key,
title text);
CREATE TABLE item_tags(
item_id int references items(id),
tag_id int references tags(id),
primary key(item_id, tag_id));
insert into items (title) values ('my title 1'), ('my title 2');
insert into tags (title) values ('tag1'), ('tag2');
insert into item_tags (item_id, tag_id) values (1,1), (1, 2);
Function:
CREATE OR REPLACE FUNCTION getItemsByTag(tags text[])
RETURNS TABLE (id bigint, title text, tag text[]) AS $$
BEGIN
IF array_length(tags, 1) > 0
THEN
EXECUTE format('
SELECT d.id, d.title, array_agg(t.title)
FROM items d
INNER JOIN item_tags dt
ON dt.item_id = d.id
INNER JOIN tags t
ON t.id = dt.tag_id
AND t.title IN (%L)
GROUP BY d.id, d.title
', array_to_string(tags, ','));
-- ELSE ...
END IF;
END;
$$ LANGUAGE plpgsql;
Call:
select getItemsByTag('{"tag1", "tag2"}');