Cómo seleccionar registros únicos por SQL

87

Cuando realizo "SELECT * FROM table" obtuve resultados como los siguientes:

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

Como puede ver, hay registros duplicados de la columna2 (el elemento1 está duplicado). Entonces, ¿cómo podría obtener un resultado como este?

1 item1 data1
2 item2 data3
3 item3 data4

Solo se devuelve un registro del duplicado, junto con el resto de los registros únicos.

Yinan
fuente
El elemento 1 no está duplicado técnicamente. Como se muestra, las filas 1 y 2 son observaciones únicas. ¿Y si quisiera mantener la fila 2 y no la fila 1?
Cibernético

Respuestas:

105

Con la distinctpalabra clave con nombres de columna única y múltiple, obtiene registros distintos:

SELECT DISTINCT column 1, column 2, ...
FROM table_name;
mjallday
fuente
14
¿Puede ser que la respuesta sea realmente incorrecta? DISTINCT se aplica a todas las columnas seleccionadas (al menos en un DB2), que aún devolverá valores duplicados en columnas individuales.
Konstantin
26

Si solo necesita eliminar duplicados, utilice DISTINCT. GROUP BYdebe usarse para aplicar operadores agregados a cada grupo

GRUPO POR V DISTINTO

rahul
fuente
11

Depende de la fila que quieras devolver para cada artículo único. Sus datos parecen indicar el valor mínimo de datos, por lo que en este caso para SQL Server.

SELECT item, min(data)
FROM  table
GROUP BY item
Dave Barker
fuente
10

Hay 4 métodos que puede utilizar:

  1. DISTINTO
  2. AGRUPAR POR
  3. Subconsulta
  4. Expresión de tabla común (CTE) con ROW_NUMBER ()

Considere la siguiente muestra TABLEcon datos de prueba:

/** 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

Opción 1: SELECT DISTINCT

Esta es la forma más simple y directa, pero también la más limitada:

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

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

Opción 2: AGRUPAR POR

Agrupación le permite añadir los datos agregados, como el 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|
*/

Opción 3: subconsulta

Con una subconsulta, primero puede identificar las filas duplicadas para ignorarlas y luego filtrarlas en la consulta externa con la WHERE NOT IN (subquery)construcción:

/** 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|
*/

Opción 4: Expresión de tabla común con ROW_NUMBER ()

En Common Table Expression (CTE), seleccione ROW_NUMBER (), dividido por la columna de grupo y ordenado en el orden deseado. Luego SELECCIONE solo los registros que tienen 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|
*/
isapir
fuente
6

solo use la unión interna porque el grupo por no funcionará con varias columnas que digan que no están contenidas en una función 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;
Ankit Kashyap
fuente
Esa es la respuesta a una pregunta diferente, probablemente una que debería etiquetarse con mayor-n-por-grupo
a_horse_with_no_name
Esta y la solución de Dave Baker son las soluciones correctas para la pregunta SO. La ventaja de esta solución es que permite seleccionar filas con solo algunas columnas distintas especificadas y una columna MIN (id) AS id debe definirse para seleccionar solo una de las múltiples columnas especificadas.
giordano
1

Encuentro que si no puedo usar DISTINCT por algún motivo, GROUP BY funcionará.

John Hamelink
fuente
1

Para obtener todas las columnas en su resultado, debe colocar algo como:

SELECT distinct a, Table.* FROM Table

colocará a como la primera columna y el resto serán TODAS las columnas en el mismo orden que su definición. Es decir, se repetirá la columna a .

htafoya
fuente
1
¿Estas seguro acerca de esto? Probé esto en w3schools y me devolvió lo mismo que SELECT *, excepto que a era la primera columna
Freakishly
@ Extrañamente sí y eso es exactamente lo que dice que hará en mi respuesta: /
htafoya
Esto no funcionará, no puede seleccionar * después de la distinción así (obtendrá un error 1064 - Error en su sintaxis SQL)
tim.baker
@Mohsinkhan bueno, olvidé colocar que debes escribir el nombre de la tabla. De alguna manera, cuando escribí esto funcionó, pero lo probé ahora y no lo hizo sin el nombre de la tabla antes del *
htafoya
2
Esto es exactamente lo mismo queselect distinct * from ...
a_horse_with_no_name
-4

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

) donde XYZ = 1 pedido por EFF_ST recupera solo las primeras 5 filas

Shailendra Singhai
fuente