¿Cómo seleccionar distinto para una columna y cualquiera en otra columna?


29

Necesito consultar una base de datos SQL para encontrar todos los valores distintos de una columna y necesito un valor arbitrario de otra columna. Por ejemplo, considere la siguiente tabla con dos columnas, clave y valor:

key     value
===     =====
one     test
one     another
one     value
two     goes
two     here
two     also
three   example

Deseo recuperar una fila de muestra, elegida arbitrariamente, de cada clave distinta, quizás obteniendo estas tres filas:

key     value
===     =====
one     test
two     goes
three   example

¿Cómo puedo formular una consulta de este tipo en SQL?


2
¿Qué DBMS (Oracle, SQL-Server, DB2, MySQL, Postgres)?
ypercubeᵀᴹ

1
Es un sistema patentado.
WilliamKF

Respuestas:


33

La consulta más fácil de escribir es para MySQL (con configuraciones ANSI no estrictas). Utiliza la construcción no estándar:

SELECT key, value
FROM tableX
GROUP BY key ;

En la versión reciente (5.7 y 8.0+) donde las configuraciones estrictas y ONLY_FULL_GROUP_BYlas predeterminadas, puede usar la ANY_VALUE()función, agregada en 5.7:

SELECT key, ANY_VALUE(value) AS value
FROM tableX
GROUP BY key ;

Para otros DBMS, que tienen funciones de ventana (como Postgres, SQL-Server, Oracle, DB2), puede usarlas así. La ventaja es que también puede seleccionar otras columnas en el resultado (además de keyy value):

SELECT key, value
FROM tableX
    ( SELECT key, value,
             ROW_NUMBER() OVER (PARTITION BY key 
                                ORDER BY whatever)     --- ORDER BY NULL
               AS rn                                   --- for example
      FROM tableX
    ) tmp 
WHERE rn = 1 ;

Para versiones anteriores de lo anterior y para cualquier otro DBMS, una forma general que funciona en casi todas partes. Una desventaja es que no puede seleccionar otras columnas con este enfoque. Otra es que las funciones agregadas tienen gusto MIN()y MAX()no funcionan con algunos tipos de datos en algunos DBMS (como bit, texto, blobs):

SELECT key, MIN(value) AS value
FROM tableX
GROUP BY key ;

PostgreSQL tiene un DISTINCT ONoperador especial no estándar que también se puede usar. La opción ORDER BYes para seleccionar qué fila de cada grupo debe seleccionarse:

SELECT DISTINCT ON (key) key, value
FROM tableX
-- ORDER BY key, <some_other_expressions> ;

2
@WilliamKF Si por "elegido arbitrariamente" quiere decir "elegido al azar", simplemente reemplace la consulta ORDER BY whateveren ypercube con una llamada a una función para aleatorizar los resultados.
Leigh Riffel

1
@LeighRiffel No tiene por qué ser aleatorio, ninguna opción, tan simple como que el primero encontrado funciona bien.
WilliamKF

3

Para el servidor MS-SQl:

;with FinalDataset as
(
    select *,
        row_number() over(partition by key order by value) as rownum
    from YourOriginalTable
)
select
   key,
   value
from FinalDataset 
where rownum = 1

Del mismo modo, podría tener rownum = 2 para su segundo conjunto de resultados


2

Similar a la respuesta aceptada, pero en lugar de min () o max () puede usar array_agg ()

SELECT key, (array_agg(value))[1] AS value
FROM tableX
GROUP BY key ;

Opcionalmente, puede ordenar valores dentro de la matriz para seleccionar el más grande o el más pequeño de ellos:

SELECT key, (array_agg(value) ORDER BY value DESC)[1] AS value
FROM tableX
GROUP BY key ;

(marcado en PostgreSQL)

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.