从子查询中选择,而不必指定GROUP BY中的所有列

时间:2017-10-04 12:39:09

标签: sql postgresql group-by

想法是查询文章具有给定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是主键)。

2 个答案:

答案 0 :(得分:1)

当您将主键包装在子查询中并且我不知道如何按照您的建议“标记”时,它可能无法正常工作。

您可以使用window functiondistinct

尝试此解决方法
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

Demo

答案 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。如果你愿意我可以举个例子。