PostgreSQL:如何选择非聚合列?

时间:2016-07-15 20:36:21

标签: sql postgresql aggregate having

似乎是一个简单的问题,但我无法完成它。我想要做的是返回所有具有重复ID的名称。视图如下:

id |  name  | other_col
---+--------+----------
 1 | James  |    x
 2 | John   |    x
 2 | David  |    x
 3 | Emily  |    x
 4 | Cameron|    x
 4 | Thomas |    x

所以在这种情况下,我只想要结果:

name
-------
John
David
Cameron
Thomas

以下查询有效,但有两个单独的选择似乎太过分了:

select name 
from view where id = ANY(select id from view 
                         WHERE other_col='x' 
                         group by id 
                         having count(id) > 1) 
      and other_col='x';

我认为应该可以按照以下方式做点什么:

select name from view WHERE other_col='x' group by id, name having count(id) > 1;

但这根本不会有任何回报!什么是'正确'的查询?

我是否只需要像我的第一个工作建议那样,还是有更好的方法?

5 个答案:

答案 0 :(得分:2)

SELECT name FROM Table
WHERE id IN (SELECT id, COUNT(*) FROM Table GROUP BY id HAVING COUNT(*)>1) Temp

答案 1 :(得分:2)

你说你想避免两个"查询",这是不可能的。有很多可用的解决方案,但我会像这样使用CTE:

WITH cte AS
(
SELECT
    id,
    name,
    other_col,
    COUNT(name) OVER(PARTITION BY id) AS id_count
FROM
    table
)

SELECT name FROM cte WHERE id_count > 1;

您可以重复使用CTE,因此您不必复制逻辑,我个人觉得更容易阅读和理解它正在做什么。

答案 2 :(得分:0)

使用EXIST运算符

SELECT * FROM table t1
WHERE EXISTS(
  SELECT null FROM table t2
  WHERE t1.id = t2.id 
    AND t1.name <> t2.name
)

答案 3 :(得分:0)

使用联接:

self.startPos

如果有超过2行共享相同的select distinct name from view v1 join view v2 on v1.id = v2.id and v1.name != v2.name ,则使用distinct。如果不可行,您可以省略id

注意:如果列distinct不唯一,则可能会引起混淆,因为它是唯一标识符列的行业标准。如果根本没有唯一的列,则会导致编码困难。

答案 4 :(得分:0)

使用CTE。这通常更昂贵,因为Postgres必须实现中间结果。

EXISTS半连接通常最快。只需确保重复谓词(或匹配值):

SELECT name 
FROM   view v
WHERE  other_col = 'x'
AND    EXISTS (
   SELECT 1 FROM view 
   WHERE  other_col = 'x' -- or: other_col = v.other_col
   AND    id <> v.id      -- exclude join to self
   );

这是一个单个查询,即使您在此处看到关键字SELECT两次。 EXISTS表达式不会生成派生表,它将被解析为简单的索引查找。

说到:(other_col, id)上的多列索引应该有所帮助。根据数据分布和访问模式,附加有效负载列name以启用仅索引扫描可能会有所帮助:(other_col, id, name)。或者甚至是部分索引, 如果 other_col = 'x'是一个常量谓词:

CREATE INDEX ON view (id) WHERE other_col = 'x';

即将推出的Postgres 9.6甚至允许对部分索引进行仅索引扫描:

CREATE INDEX ON view (id, name) WHERE other_col = 'x';

你将这一改进(quoting the /devel manual):

  

在索引时允许使用带有部分索引的index-only scan   谓词涉及未存储在索引中的列(Tomas Vondra,   Kyotaro Horiguchi)

     

如果查询提到此类列,则现在允许仅索引扫描   仅在与索引谓词匹配的WHERE子句中

使用EXPLAIN (ANALYZE, TIMING OFF) SELECT ...验证效果 运行几次以排除缓存效果。