DISTINCT 和 DISTINCT ON 的语义完全不同。
先说理论
DISTINCT 适用于整个元组。一旦计算出查询结果,DISTINCT 就会从结果中删除所有重复的元组。
例如,假设一个表 R 包含以下内容:
#table r;
a | b
---+---
1 | a
2 | b
3 | c
3 | d
2 | e
1 | a
(6 行)
SELECT distinct * from R 将导致:
# select distinct * from r;
a | b
---+---
1 | a
3 | d
2 | e
2 | b
3 | c
(5 rows)
请注意,distinct 适用于整个投影属性列表:因此
select distinct * from R
在语义上等价于
select distinct a,b from R
你不能发行
select a, distinct b From R
DISTINCT 必须跟在 SELECT 之后。它适用于整个元组,而不是结果的属性。
DISTINCT ON 是对 postgresql 语言的补充。分组依据相似,但不相同。
它的语法是:
SELECT DISTINCT ON (attributeList) <rest as any query>
例如:
SELECT DISTINCT ON (a) * from R
它的语义可以描述如下。像往常一样计算查询——没有 DISTINCT ON (a)——但在结果的投影之前,对当前结果进行排序并根据 DISTINCT ON 中的属性列表对其进行分组(类似于 group by)。现在,使用每个组中的第一个元组进行投影并忽略其他元组。
例子:
select distinct * from r order by a;
a | b
---+---
1 | a
2 | e
2 | b
3 | c
3 | d
(5 rows)
然后对于每个不同的 a 值,取第一个元组。与以下内容相同:
SELECT DISTINCT on (a) * from r;
a | b
---+---
1 | a
2 | b
3 | c
(3 rows)
一些 DBMS(尤其是 sqlite)将允许您运行此查询:
SELECT a,b from R group by a;
这会给你类似的结果。
当且仅当存在从 a 到 b 的函数依赖时,Postgresql 才会允许此查询。换句话说,如果对于关系 R 的任何实例,每个值或 a 只有一个唯一元组,则此查询将有效(因此选择第一个元组是确定性的:只有一个元组)。
例如,如果 R 的主键是 a,那么 a->b 和:
SELECT a,b FROM R group by a
等同于:
SELECT DISTINCT on (a) a, b from r;
现在,回到你的问题:
第一个查询:
SELECT DISTINCT count(dimension1)
FROM data_table;
计算维度 1 的计数(data_table 中维度 1 不为空的元组数)。这个查询
返回一个元组,它总是唯一的(因此 DISTINCT
是多余的)。
查询 2:
SELECT count(*)
FROM (SELECT DISTINCT ON (dimension1) dimension1
FROM data_table
GROUP BY dimension1) AS tmp_table;
这是查询中的查询。为了清楚起见,让我重写一下:
WITH tmp_table AS (
SELECT DISTINCT ON (dimension1)
dimension1 FROM data_table
GROUP by dimension1)
SELECT count(*) from tmp_table
让我们首先计算 tmp_table。正如我上面提到的,
让我们首先忽略 DISTINCT ON 并做剩下的
询问。这是按维度 1 分组的。因此这部分查询
每个维度 1 的不同值将产生一个元组。
现在,DISTINCT 开启。它再次使用维度1。但是 dimension1 已经是唯一的(由于 group by)。因此
这使得 DISTINCT ON superflouos (它什么都不做)。
最终计数只是 group by 中所有元组的计数。
如您所见,以下查询中存在等价关系(它适用于具有属性 a 的任何关系):
SELECT (DISTINCT ON a) a
FROM R
和
SELECT a FROM R group by a
和
SELECT DISTINCT a FROM R
警告
在查询中使用 DISTINCT ON 结果对于任何给定的数据库实例可能是不确定的。
换句话说,查询可能会为相同的表返回不同的结果。
一个有趣的方面
Distinct ON 以更简洁的方式模拟了 sqlite 的 bad 行为。假设R有两个属性a和b:
SELECT a, b FROM R group by a
是 SQL 中的非法语句。然而,它在 sqlite 上运行。它只是从 a 的相同值组中的任何元组中获取 b 的随机值。
在 Postgresql 中,这条语句是非法的。相反,您必须使用 DISTINCT ON 并编写:
SELECT DISTINCT ON (a) a,b from R
推论
当您想要访问在功能上依赖于 group by 属性的值时,DISTINCT ON 在 group by 中很有用。换句话说,如果您知道对于每组属性,它们始终具有与第三个属性相同的值,那么在该组属性上使用 DISTINCT。否则,您必须进行 JOIN 才能检索第三个属性。