Как выбрать разные для одного столбца и любого другого столбца?

29

Мне нужно запросить базу данных SQL, чтобы найти все различные значения одного столбца, и мне нужно произвольное значение из другого столбца. Например, рассмотрим следующую таблицу с двумя столбцами, ключом и значением:

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

Я хочу получить по одной выборочной строке, выбранной произвольно, из каждого отдельного ключа, возможно, получая эти три строки:

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

Как я могу сформулировать такой запрос в SQL?

WilliamKF
источник
2
Какие СУБД (Oracle, SQL-сервер, DB2, MySQL, Postgres)?
ypercubeᵀᴹ
1
Это проприетарная система.
WilliamKF

Ответы:

33

Самый простой запрос для записи - для MySQL (с не строгими настройками ANSI). Используется нестандартная конструкция:

SELECT key, value
FROM tableX
GROUP BY key ;

В последних версиях (5.7 и 8.0+), где строгие настройки и ONLY_FULL_GROUP_BYявляются настройками по умолчанию, вы можете использовать ANY_VALUE()функцию, добавленную в 5.7:

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

Для других СУБД, которые имеют оконные функции (например, Postgres, SQL-Server, Oracle, DB2), вы можете использовать их следующим образом. Преимущество в том, что вы можете выбрать и другие столбцы в результате (кроме keyи 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 ;

Для более старых версий выше и для любой другой СУБД, общий способ, который работает почти везде. Одним из недостатков является то, что вы не можете выбрать другие столбцы с этим подходом. Другое - агрегатные функции, такие как MIN()и MAX()не работающие с некоторыми типами данных в некоторых СУБД (например, бит, текст, большие двоичные объекты):

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

PostgreSQL имеет специальный нестандартный DISTINCT ONоператор, который также можно использовать. Необязательный ORDER BYдля выбора строки из каждой группы:

SELECT DISTINCT ON (key) key, value
FROM tableX
-- ORDER BY key, <some_other_expressions> ;
ypercubeᵀᴹ
источник
2
@WilliamKF Если под «выбран произвольно» вы подразумеваете «выбран случайно», то просто замените ORDER BY whateverзапрос в ypercube на вызов функции для рандомизации результатов.
Ли Риффель
1
@LeighRiffel Это не должно быть случайным, любой выбор, так же просто, как первый, который встречается, работает отлично.
WilliamKF
3

Для сервера 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

Точно так же вы могли бы иметь rownum = 2 для вашего второго набора результатов

JP Chauhan
источник
2

Аналогично принятому ответу, но вместо min () или max () вы можете использовать array_agg ()

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

Вы можете при желании упорядочить значения внутри массива, чтобы выбрать самые большие или самые маленькие из них:

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

(проверено на PostgreSQL)

alexkovelsky
источник