Como selecionar registros únicos por SQL


87

Quando eu executo "SELECT * FROM table", obtive resultados como abaixo:

1 item1 data1
2 item1 data2
3 item2 data3
4 item3 data4

Como você pode ver, existem registros dup da coluna2 (item1 são duplicados). Então, como eu poderia obter resultados como este:

1 item1 data1
2 item2 data3
3 item3 data4

Apenas um registro é retornado da duplicata, junto com o restante dos registros exclusivos.


O item 1 não é tecnicamente duplicado. Conforme mostrado, as linhas 1 e 2 são observações únicas. E se você quisesse manter a linha 2 e não a linha 1?
— Cybernetic

Respostas:


105

Com a distinctpalavra-chave com nomes de coluna única e múltipla, você obtém registros distintos:

SELECT DISTINCT column 1, column 2, ...
FROM table_name;

14
Será que a resposta está realmente errada? DISTINCT é aplicado a todas as colunas selecionadas (pelo menos em um DB2), que ainda retornará valores duplicados em colunas individuais.
— Konstantin

26

Se você só precisa remover duplicatas, use DISTINCT. GROUP BYdeve ser usado para aplicar operadores agregados a cada grupo

GROUP BY v DISTINCT


11

Depende de qual linha você deseja devolver para cada item exclusivo. Seus dados parecem indicar o valor mínimo dos dados, nesta instância do SQL Server.

SELECT item, min(data)
FROM  table
GROUP BY item

10

Existem 4 métodos que você pode usar:

  1. DISTINTO
  2. GRUPO POR
  3. Subconsulta
  4. Expressão de tabela comum (CTE) com ROW_NUMBER ()

Considere o seguinte exemplo TABLEcom dados de teste:

/** Create test table */
CREATE TEMPORARY TABLE dupes(word text, num int, id int);

/** Add test data with duplicates */
INSERT INTO dupes(word, num, id)
VALUES ('aaa', 100, 1)
      ,('bbb', 200, 2)
      ,('ccc', 300, 3)
      ,('bbb', 400, 4)
      ,('bbb', 200, 5)     -- duplicate
      ,('ccc', 300, 6)     -- duplicate
      ,('ddd', 400, 7)
      ,('bbb', 400, 8)     -- duplicate
      ,('aaa', 100, 9)     -- duplicate
      ,('ccc', 300, 10);   -- duplicate

Opção 1: SELECIONE DISTINTO

Esta é a maneira mais simples e direta, mas também a mais limitada:

SELECT DISTINCT word, num 
FROM    dupes
ORDER BY word, num;

/*
word|num|
----|---|
aaa |100|
bbb |200|
bbb |400|
ccc |300|
ddd |400|
*/

Opção 2: GROUP BY

Agrupamento permite que você adicione dados agregados, como o min(id), max(id), count(*), etc:

SELECT  word, num, min(id), max(id), count(*)
FROM    dupes
GROUP BY word, num
ORDER BY word, num;

/*
word|num|min|max|count|
----|---|---|---|-----|
aaa |100|  1|  9|    2|
bbb |200|  2|  5|    2|
bbb |400|  4|  8|    2|
ccc |300|  3| 10|    3|
ddd |400|  7|  7|    1|
*/

Opção 3: subconsulta

Usando uma subconsulta, você pode primeiro identificar as linhas duplicadas a serem ignoradas e, em seguida, filtrá-las na consulta externa com a WHERE NOT IN (subquery)construção:

/** Find the higher id values of duplicates, distinct only added for clarity */
    SELECT  distinct d2.id
    FROM    dupes d1
        INNER JOIN dupes d2 ON d2.word=d1.word AND d2.num=d1.num
    WHERE d2.id > d1.id

/*
id|
--|
 5|
 6|
 8|
 9|
10|
*/

/** Use the previous query in a subquery to exclude the dupliates with higher id values */
SELECT  *
FROM    dupes
WHERE   id NOT IN (
    SELECT  d2.id
    FROM    dupes d1
        INNER JOIN dupes d2 ON d2.word=d1.word AND d2.num=d1.num
    WHERE d2.id > d1.id
)
ORDER BY word, num;

/*
word|num|id|
----|---|--|
aaa |100| 1|
bbb |200| 2|
bbb |400| 4|
ccc |300| 3|
ddd |400| 7|
*/

Opção 4: Expressão de tabela comum com ROW_NUMBER ()

Na Expressão de Tabela Comum (CTE), selecione ROW_NUMBER (), particionado pela coluna do grupo e ordenado na ordem desejada. Em seguida, SELECIONE apenas os registros que possuem ROW_NUMBER() = 1:

WITH CTE AS (
    SELECT  *
           ,row_number() OVER(PARTITION BY word, num ORDER BY id) AS row_num
    FROM    dupes
)
SELECT  word, num, id 
FROM    cte
WHERE   row_num = 1
ORDER BY word, num;

/*
word|num|id|
----|---|--|
aaa |100| 1|
bbb |200| 2|
bbb |400| 4|
ccc |300| 3|
ddd |400| 7|
*/

6

apenas use a junção interna porque agrupar por não funcionará com várias colunas dizendo que não está contido em nenhuma função agregada.

SELECT a.*
FROM yourtable a
INNER JOIN 
  (SELECT yourcolumn,
    MIN(id) as id
  FROM yourtable 
  GROUP BY yourcolumn
) AS b
  ON a.yourcolumn= b.yourcolumn
  AND a.id = b.id;

Essa é a resposta para uma pergunta diferente, provavelmente uma que deveria ser marcada com maior-n-por-grupo
— a_horse_with_no_name

Esta e a solução de Dave Baker são as soluções corretas para a questão do SO. A vantagem desta solução é que ela permite selecionar linhas com apenas algumas colunas distintas especificadas e uma coluna MIN (id) AS id deve ser definida para selecionar apenas uma das múltiplas colunas especificadas.
— giordano

1

Acho que, se não conseguir usar o DISTINCT por algum motivo, o GROUP BY funcionará.


1

Para obter todas as colunas em seu resultado, você precisa colocar algo como:

SELECT distinct a, Table.* FROM Table

ele colocará um como a primeira coluna e o resto será TODAS as colunas na mesma ordem de sua definição. Ou seja, a coluna a será repetida.


1
Você tem certeza disso? Eu tentei isso em w3schools e retornou o mesmo que SELECT *, exceto que a era a primeira coluna
— Freakishly

@Freakishly yes e isso é exatamente o que diz que fará na minha resposta: /
— htafoya

Isso não funcionará, você não pode selecionar * após o distinto como esse (você receberá um erro 1064 - Erro em sua sintaxe SQL)
— tim.baker

@Mohsinkhan bem esqueci de colocar que você precisa para escrever o nome da tabela. De alguma forma, quando eu escrevi isso funcionou, mas eu apenas testei agora e não funcionou sem o nome da tabela antes de *
— htafoya

2
É exatamente igual aselect distinct * from ...
— a_horse_with_no_name

-4

Selecione Eff_st de (selecione EFF_ST, ROW_NUMBER () sobre (PARTITION BY eff_st) XYZ - de ABC.CODE_DIM

) onde XYZ = 1 pedido por EFF_ST busca as primeiras 5 linhas apenas

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.