仅选择组中所有元素具有相同值的组

时间:2018-06-17 14:27:51

标签: sql postgresql aggregate

将PostgreSQL与pgadmin4一起使用,我有一个像这样的示例表:

dogs

+---+-------------------+------------+
|id |breed              | birthPlace |
+---+-------------------+------------+
| 1 | Yorkshire Terrier | Berlin     |
| 2 | Yorkshire Terrier | Berlin     |
| 3 | Husky             | New York   |
| 4 | Yorkshire Terrier | Berlin     |
| 5 | Husky             | Amsterdam  |
+---+-------------------+------------+

对于练习,我想通过breed对我的桌子进行分组,确保至少有两只狗的一个品种,然后扔出所有组,其狗不是都有相同的{{1} 1}}。

我想我必须在下面的查询中设置birthPlace所在的最后一个语句,但我对如何执行此操作一无所知:

?

4 个答案:

答案 0 :(得分:4)

我想说的如下:

SELECT breed
FROM dogs
GROUP BY breed
HAVING COUNT(*) > 1 AND COUNT(DISTINCT birthPlace) = 1;
       ^^^ at least two dogs      ^^^ same birthplace

HAVING条款声称每个品种至少有两只狗,并且该品种只有一个不同的出生地。

答案 1 :(得分:2)

没有相同的出生地意味着最小值和最大值不同。这应该是如何解决问题的一个很大的暗示。

这很容易翻译成SQL:

Having Count(*) > 1 And min(birthPlace) <> max(birthPlace)

注意我已将COUNT(dogs.id)更改为COUNT(*)。那些应该做同样的事情,COUNT(*)更容易打字和阅读。

您可能想要使用count(distinct birthplace)。我不鼓励这样做。当您不需要时,请避免使用distinct,因为它通常会产生比“更简单”更多的开销。聚合函数。

最后,这两种方法都忽略NULL个值。可以通过包括and count(birthplace) = count(*)来包含所有值都为非NULL的要求。

答案 2 :(得分:2)

带子查询的变体:

SELECT breed
FROM  (
   SELECT breed, birthPlace, count(*)::int AS ct
   FROM   dogs
   GROUP  BY 1, 2
   ) sub
GROUP  BY 1
HAVING count(*) = 1  -- one birth place
AND    sum(ct) > 1;  -- more than one row

应该是最快的技术之一。

强制转换为整数(::int)是可选的。避免升级到外部numeric中的数据类型SELECT。没关系。

答案 3 :(得分:0)

plsql中你必须做这样的事情(假设id不是真正的列):

With que as
(
  SELECT breed, birthplace, count(distinct birthplace) over (partition by breed) counter
  FROM dog
)
SELECT breed, birthplace 
FROM que
WHERE counter = 1
GROUP BY breed, birthplace, counter
HAVING count(breed) > 1