我有一个使用以下语句创建的Postgres表。此表由另一个服务的数据转储填充。
CREATE TABLE data_table (
date date DEFAULT NULL,
dimension1 varchar(64) DEFAULT NULL,
dimension2 varchar(128) DEFAULT NULL
) TABLESPACE pg_default;
我正在构建的ETL中的一个步骤是提取dimension1
的唯一值并将它们插入另一个中间表中。
但是,在某些测试中,我发现下面的2个命令不会返回相同的结果。我希望两者都返回相同的金额。
与第二个命令相比,第一个命令返回的结果更多(1466行对1504。
-- 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;
谢谢!
答案 0 :(得分:11)
DISTINCT和DISTINCT ON具有完全不同的语义。
首先是理论
DISTINCT适用于整个元组。一旦计算出查询结果,DISTINCT就会从结果中删除任何重复的元组。
例如,假设一个表R包含以下内容:
#table r;
a | b
---+---
1 | a
2 | b
3 | c
3 | d
2 | e
1 | a
(6行)
从R中选择distinct *将导致:
# 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中的属性列表对当前结果进行排序并对其进行分组(类似于分组依据)。现在,使用每个组中的第一个元组进行投影,并忽略其他元组。
示例:
SELECT DISTINCT on (a) * from r;
a | b
---+---
1 | a
2 | b
3 | c
(3 rows)
现在,回到你的问题:
首先查询:
SELECT DISTINCT count(dimension1)
FROM data_table;
计算dimension1的计数(data_table中的元组数,其中dimension1不为null)。这个查询 返回一个元组,它总是唯一的(因此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 ON。它再次使用dimension1。但是dimension1已经是唯一的(由于分组)。于是 这使得DISTINCT ON superflouos(它什么都不做)。 最终计数只是该组中所有元组的计数。
如您所见,以下查询中存在等价(它适用于具有属性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和mysql的错误行为。假设R有两个属性a和b:
SELECT a, b FROM R group by a
是SQL中的非法语句。然而,它运行在mysql和sqlite上。它只是从a的相同值组中的任何元组中获取b的随机值。 在Postgresql中,这种说法是非法的。相反,您必须使用DISTINCT ON并写:
SELECT DISTINCT ON (a) a,b from R
*推论*
当您想要访问功能上依赖于属性组的值时,DISTINCT ON在组中很有用。换句话说,如果您知道对于每组属性,它们始终具有与第三个属性相同的值,则对该组属性使用DISTINCT。否则,您必须进行JOIN才能检索第三个属性。
答案 1 :(得分:2)
第一个查询给出AlphaType.click();
AlphaType.findElement(By.xpath("//div[@id='home-tabs-pane-0']/div/div[4]/div[3]/div[2]/div/div/div/form/div[3]/div[2]/ul/li[3]/a/span")).click();
Thread.sleep(2000);
的非空值的数量,而第二个查询返回列的不同值的数量。如果列包含重复项或空值,则这些数字显然不相等。
中的
dimension1
字样
DISTINCT
没有意义,因为查询返回单行。也许你想要
SELECT DISTINCT count(dimension1)
FROM data_table;
返回SELECT count(DISTINCT dimension1)
FROM data_table;
的不同非空值的数量。请注意,它与
dimension1
最后一个查询产生列的所有(空或非)不同值的数量。
答案 2 :(得分:0)
尝试
SELECT count(dimension1a)
FROM (SELECT DISTINCT ON (dimension1) dimension1a
FROM data_table
ORDER BY dimension1) AS tmp_table;
DISTINCT ON似乎与GROUP BY同义。
答案 3 :(得分:0)
学习和理解视觉例子会发生什么 这是在PostgreSQL上执行的一些SQL:
DROP TABLE IF EXISTS test_table;
CREATE TABLE test_table (
id int NOT NULL primary key,
col1 varchar(64) DEFAULT NULL
);
INSERT INTO test_table (id, col1) VALUES
(1,'foo'), (2,'foo'), (3,'bar'), (4,null);
select count(*) as total1 from test_table;
-- returns: 4
-- Because the table has 4 records.
select distinct count(*) as total2 from test_table;
-- returns: 4
-- The count(*) is just one value. Making 1 total unique can only result in 1 total.
-- So the distinct is useless here.
select col1, count(*) as total3 from test_table group by col1 order by col1;
-- returns 3 rows: ('bar',1),('foo',2),(NULL,1)
-- Since there are 3 unique col1 values. NULL's are included.
select distinct col1, count(*) as total4 from test_table group by col1 order by col1;
-- returns 3 rows: ('bar',1),('foo',2),(NULL,1)
-- The result is already grouped, and therefor already unique.
-- So again, the distinct does nothing extra here.
select count(distinct col1) as total5 from test_table;
-- returns 2
-- NULL's aren't counted in a count by value. So only 'foo' & 'bar' are counted
select distinct on (col1) id, col1 from test_table order by col1 asc, id desc;
-- returns 3 rows: (2,'a'),(3,'b'),(4,NULL)
-- So it gets the records with the maximum id per unique col1
-- Note that the "order by" matters here. Changing that DESC to ASC would get the minumum id.
select count(*) as total6 from (select distinct on (col1) id, col1 from test_table order by col1 asc, id desc) as q;
-- returns 3.
-- After seeing the previous query, what else would one expect?
select distinct col1 from test_table order by col1;
-- returns 3 unique values : ('bar'),('foo'),(null)
select distinct id, col1 from test_table order by col1;
-- returns all records.
-- Because id is the primary key and therefore makes each returned row unique