想法是查询文章具有给定article
的{{1}}表,然后查询属于该文章行的所有(甚至无关的)标记{/ 1}}。
示例表和查询:
tag
运行上述内容,postgres要求STRING_AGG
必须包含CREATE TABLE article (id SERIAL, body TEXT);
CREATE TABLE article_tag (article INT, tag INT);
CREATE TABLE tag (id SERIAL, title TEXT);
SELECT DISTICT ON (id)
q.id, q.body, STRING_AGG(q.tag_title, '|') tags
FROM (
SELECT a.*, tag.title tag_title
FROM article a
LEFT JOIN article_tag x ON a.id = tag.article
LEFT JOIN tag ON tag.id = x.tag
WHERE tag.title = 'someTag'
) q
GROUP BY q.id
:
q.body
据我了解,这是因为子查询GROUP BY
不包含任何PRIMARY键。
我天真地认为ERROR: column "q.body" must appear in the GROUP BY clause or be used in an aggregate function
会补充这一点,但似乎并非如此。
有没有办法将子查询中的列标记为PRIMARY,这样我们就不必列出q
子句中的所有列?
如果我们做必须列出DISTINCT ON
子句中的所有列,是否会产生显着的性能成本?
编辑详细说明,因为PostgreSQL 9.1您不必提供非主要(功能相关)使用GROUP BY
时的键,例如以下查询工作正常:
GROUP BY
我想知道我是否可以使用相同的行为,但与子查询(以某种方式表明GROUP BY
是主键)。
答案 0 :(得分:1)
当您将主键包装在子查询中并且我不知道如何按照您的建议“标记”时,它可能无法正常工作。
您可以使用window function
和distinct
CREATE TABLE test1 (id serial primary key, name text, value text);
CREATE TABLE test2 (id serial primary key, test1_id int, value text);
INSERT INTO test1(name, value)
values('name1', 'test01'), ('name2', 'test02'), ('name3', 'test03');
INSERT INTO test2(test1_id, value)
values(1, 'test1'), (1, 'test2'), (3, 'test3');
SELECT DISTINCT ON (id) id, name, string_agg(value2, '|') over (partition by id)
FROM (SELECT test1.*, test2.value AS value2
FROM test1
LEFT JOIN test2 ON test2.test1_id = test1.id) AS sub;
id name string_agg
1 name1 test1|test2
2 name2 null
3 name3 test3
答案 1 :(得分:0)
问题出在外部SELECT
- 您应该聚合列
由他们组成。 Postgres希望您指定如何处理q.body
- 按组分组或计算聚合。看起来有点尴尬,但应该工作。
SELECT DISTICT ON (id)
q.id, q.body, STRING_AGG(q.tag_title, '|') tags
FROM (
SELECT a.*, tag.title tag_title
FROM article a
LEFT JOIN article_tag x ON a.id = tag.article
LEFT JOIN tag ON tag.id = x.tag
WHERE tag.title = 'someTag'
) q
GROUP BY q.id, q.body
-- ^^^^^^
另一种方法是进行查询以获取id
并汇总tags
,然后加入body
。如果你愿意我可以举个例子。