我用下面的语句创建了一个Postgres表.此表由另一个服务的数据转储填写.

CREATE TABLE data_table (
    date date DEFAULT NULL,
    dimension1 varchar(64) DEFAULT NULL,
    dimension2 varchar(128) DEFAULT NULL
) TABLESPACE pg_default;

我构建的ETL中的一个步骤是提取dimension1的唯一值,并将其插入另一个中间表中.

-- command 1
SELECT DISTINCT count(dimension1)
FROM data_table;

-- command 2    
SELECT count(*)
FROM (SELECT DISTINCT ON (dimension1) dimension1
FROM data_table
GROUP BY dimension1) AS tmp_table;

有什么明显的解释吗?除了解释,还有什么建议我应该判断数据吗?

编辑:以下查询都返回1504(与"简单"DISTINCT相同)

SELECT count(*)
FROM data_table WHERE dimension1 IS NOT NULL;

SELECT count(dimension1)
FROM data_table;

非常感谢.

推荐答案

DISTINCT 和 DISTINCT ON have completely different semantics.

First the theory

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对该语言的补充.它与group by相似,但不完全相同.

它的语法是:

 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只有一个唯一元组,则此查询将有效(因此, Select 第一个元组是确定的:只有一个元组).

例如,如果R的主键是a,那么a->;b和:

SELECT a,b FROM R group by a

与以下内容相同:

  SELECT DISTINCT on (a) a, b from r;

Now, back to your problem:

第一个问题:

SELECT DISTINCT count(dimension1)
FROM data_table;

计算维度1的计数(数据表中维度1不为空的元组数).这个问题

问题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_表.正如我上面提到的,

现在,我们开始了.它再次使用维度1.但是dimension1已经是唯一的了(因为group by).因此

正如您所看到的,以下查询中存在一个等价关系(它适用于具有属性a的任何关系):

SELECT (DISTINCT ON a) a
FROM R

SELECT a FROM R group by a

SELECT DISTINCT a FROM R

Warning

对于数据库的任何给定实例,在查询中使用DISTINCT ON结果可能是不确定的.

One interesting aspect

Distinct ON emulates a bad behaviour of sqlite in a much cleaner way. Assume that R has two attributes a 和 b:

SELECT a, b FROM R group by a

is an illegal statement in SQL. Yet, it runs on sqlite. It simply takes a r和om value of b from any of the tuples in the group of same values of a. In Postgresql this statement is illegal. Instead, you must use DISTINCT ON 和 write:

SELECT DISTINCT ON (a) a,b from R

100

当需要访问功能上依赖于group by属性的值时,DISTINCT ON在group by中非常有用.换句话说,如果您知道对于每一组属性,它们总是具有与第三个属性相同的值,那么在该组属性上使用DISTINCT.否则,必须进行连接才能检索第三个属性.

Postgresql相关问答推荐

为什么在使用PostGIS时,英国郡的几何图形会出现在几内亚湾?

为MCV扩展统计设置统计目标

EF Core和npgsql连接池已被耗尽

postgres hierarchy - 用祖先的值填充缺失值

如何创建一个触发器来传播对主键表的更新?

是否可以在 postgres jsonb 列中的列表上创建索引

使用 select 在带有特殊字符的字符串中查找数据

Postgres 低估了导致错误查询计划的行数

订阅标签保存在哪个表中?

GORM 不会创建 many2many 关联

如何将 NULL 值插入 UUID 而不是零

如何展平也在关系中使用的区分大小写的列

如何防止 PDO 将问号解释为占位符?

我应该使用哪个 postgresql 包?

在 postgres 中Decode解码相似的函数

LAG 函数和 GROUP BY

'active' 标志与否?

错误:ERROR: table name specified more than once

PL/pgSQL 执行与执行

Capistrano 与 PostgreSQL,错误:database is being accessed by other users