似乎是一个简单的问题,但我无法完成它。我想要做的是返回所有具有重复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;
但这根本不会有任何回报!什么是'正确'的查询?
我是否只需要像我的第一个工作建议那样,还是有更好的方法?
答案 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 ...
验证效果
运行几次以排除缓存效果。