我想根据items
创建一个返回tags
的函数。但是,我不知道如何在IN()
子句中格式化数组。我相信这就是我没有结果的原因。
这是我得到的:
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;
然后我打电话:
select getItemsByTag('{"gaming", "sport"}');
即使有标记为“游戏”的项目,我也没有结果。
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);
功能:
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;
致电:
select getItemsByTag('{"tag1", "tag2"}');
答案 0 :(得分:0)
尝试在tags
声明中使用format
来代替:{
'''' || array_to_string(tags, "','") || ''''
> IN子句中的结果将类似于IN ('gaming','sport')
。
答案 1 :(得分:0)
这是因为我没有回任何东西。
return query 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 = ANY(%L)
GROUP BY d.id, d.title
', tags) ;
答案 2 :(得分:0)
您实际上并非 返回 结果。您可以使用RETURN QUERY EXECUTE
。例如:
但是你不需要动态SQL来开始......
CREATE OR REPLACE FUNCTION get_items_by_tag(VARIADIC tags text[])
RETURNS TABLE (id int, title text, tag text[]) AS
$func$
BEGIN
IF array_length(tags, 1) > 0 THEN
-- NO need for EXECUTE
RETURN QUERY
SELECT d.id, d.title, array_agg(t.title)
FROM items d
JOIN item_tags dt ON dt.item_id = d.id
JOIN tags t ON t.id = dt.tag_id
AND t.title = ANY ($1) -- use ANY construct
GROUP BY d.id; -- PK covers whole table
-- array_to_string(tags, ',') -- no need to convert array with ANY
-- ELSE ...
END IF;
END
$func$ LANGUAGE plpgsql;
使用实际数组调用:
SELECT * FROM get_items_by_tag(VARIADIC '{tag1,tag2}'::text[]);
或调用项目列表("字典"):
SELECT * FROM get_items_by_tag('tag1', 'tag2');
使用RETURN QUERY
实际返回结果行。
除非您需要,否则不要使用动态SQL。 (这里没有EXECUTE
。)
使用ANY
结构而不是IN
。为什么呢?
为方便起见,我建议使用VARIADIC
函数。这样,您可以根据自己的选择传递数组或项列表。参见:
如果可能,请避免在Postgres中使用混合大小写标识符。
不确定您为何拥有IF array_length(tags, 1) > 0 THEN
,但可能会被IF tags IS NOT NULL THEN
或IF
取代,并跟进IF NOT FOUND THEN
。更多: