Як вибрати відмінність для одного стовпця та будь-якого в іншому стовпці?


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?


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-сервер, 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> ;

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 для другого набору результатів


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)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.