DISTINCT e DISTINCT ON têm semânticas completamente diferentes.
Primeiro a teoria
DISTINCT se aplica a uma tupla inteira. Depois que o resultado da consulta é calculado, DISTINCT remove quaisquer tuplas duplicadas do resultado.
Por exemplo, suponha uma tabela R com o seguinte conteúdo:
#table r;
a | b
---+---
1 | a
2 | b
3 | c
3 | d
2 | e
1 | a
(6 linhas)
SELECT distinto * de R resultará:
# select distinct * from r;
a | b
---+---
1 | a
3 | d
2 | e
2 | b
3 | c
(5 rows)
Observe que distinct se aplica a toda a lista de atributos projetados:assim
select distinct * from R
é semanticamente equivalente a
select distinct a,b from R
Você não pode emitir
select a, distinct b From R
DISTINCT deve seguir SELECT. Aplica-se à tupla inteira, não a um atributo do resultado.
DISTINTO LIGADO é uma adição postgresql à linguagem. É semelhante, mas não idêntico, agrupar por.
Sua sintaxe é:
SELECT DISTINCT ON (attributeList) <rest as any query>
Por exemplo:
SELECT DISTINCT ON (a) * from R
A semântica pode ser descrita da seguinte forma. Calcule a consulta como de costume -- sem o DISTINCT ON (a) --- mas antes da projeção do resultado, ordene o resultado atual e agrupe-o de acordo com a lista de atributos em DISTINCT ON (semelhante a agrupar por). Agora, faça a projeção usando a primeira tupla de cada grupo e ignore as outras tuplas.
Exemplo:
select distinct * from r order by a;
a | b
---+---
1 | a
2 | e
2 | b
3 | c
3 | d
(5 rows)
Então, para cada valor diferente de a, pegue a primeira tupla. Que é o mesmo que:
SELECT DISTINCT on (a) * from r;
a | b
---+---
1 | a
2 | b
3 | c
(3 rows)
Alguns DBMS (principalmente sqlite) permitirão que você execute esta consulta:
SELECT a,b from R group by a;
E isso lhe dá um resultado semelhante.
O Postgresql permitirá esta consulta, se e somente se houver uma dependência funcional de a para b. Em outras palavras, esta consulta será válida se para qualquer instância da relação R, houver apenas uma tupla única para cada valor ou a (portanto, selecionar a primeira tupla é determinístico:há apenas uma tupla).
Por exemplo, se a chave primária de R for a, então a->b e:
SELECT a,b FROM R group by a
é idêntico a:
SELECT DISTINCT on (a) a, b from r;
Agora, de volta ao seu problema:
Primeira consulta:
SELECT DISTINCT count(dimension1)
FROM data_table;
calcula a contagem de dimension1 (número de tuplas em data_table onde dimension1 não é nulo). Esta consulta retorna uma tupla, que é sempre única (portanto, DISTINCT é redundante).
Pergunta 2:
SELECT count(*)
FROM (SELECT DISTINCT ON (dimension1) dimension1
FROM data_table
GROUP BY dimension1) AS tmp_table;
Esta é uma consulta em uma consulta. Deixe-me reescrevê-lo para maior clareza:
WITH tmp_table AS (
SELECT DISTINCT ON (dimension1)
dimension1 FROM data_table
GROUP by dimension1)
SELECT count(*) from tmp_table
Vamos calcular primeiro tmp_table. Como mencionei acima, vamos primeiro ignorar o DISTINCT ON e fazer o resto da consulta. Este é um grupo por dimensão1. Portanto, essa parte da consulta resultará em uma tupla por valor diferente de dimension1.
Agora, o DISTINTO ON. Ele usa dimension1 novamente. Mas dimension1 já é único (devido ao group by). Portanto, isso torna o DISTINCT ON superflouos (não faz nada). A contagem final é simplesmente uma contagem de todas as tuplas do grupo por.
Como você pode ver, há uma equivalência na seguinte consulta (aplica-se a qualquer relação com um atributo a):
SELECT (DISTINCT ON a) a
FROM R
e
SELECT a FROM R group by a
e
SELECT DISTINCT a FROM R
Aviso
O uso de resultados DISTINCT ON em uma consulta pode ser não determinístico para qualquer instância do banco de dados. Em outras palavras, a consulta pode retornar resultados diferentes para as mesmas tabelas.
Um aspecto interessante
Distinct ON emula um ruim comportamento do sqlite de uma forma muito mais limpa. Suponha que R tenha dois atributos a e b:
SELECT a, b FROM R group by a
é uma instrução ilegal em SQL. No entanto, ele é executado em sqlite. Ele simplesmente pega um valor aleatório de b de qualquer uma das tuplas no grupo de mesmos valores de a. No Postgresql esta declaração é ilegal. Em vez disso, você deve usar DISTINCT ON e escrever:
SELECT DISTINCT ON (a) a,b from R
Corolário
DISTINCT ON é útil em um grupo por quando você deseja acessar um valor que é funcionalmente dependente do grupo por atributos. Em outras palavras, se você sabe que para cada grupo de atributos eles sempre têm o mesmo valor do terceiro atributo, então use DISTINCT ON nesse grupo de atributos. Caso contrário, você teria que fazer um JOIN para recuperar esse terceiro atributo.