Jak wybrać odrębne dla jednej kolumny i dowolnej w innej kolumnie?

29

Muszę wysłać zapytanie do bazy danych SQL, aby znaleźć wszystkie odrębne wartości jednej kolumny, i potrzebuję dowolnej wartości z innej kolumny. Rozważmy na przykład poniższą tabelę z dwiema kolumnami, kluczem i wartością:

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

Chcę odzyskać jeden przykładowy wiersz, wybrany dowolnie, z każdego odrębnego klucza, być może otrzymując te trzy wiersze:

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

Jak sformułować takie zapytanie w SQL?

WilliamKF
źródło
2
Który DBMS (Oracle, SQL-Server, DB2, MySQL, Postgres)?
ypercubeᵀᴹ
1
Jest to zastrzeżony system.
WilliamKF,

Odpowiedzi:

33

Najłatwiejsze do napisania zapytanie dotyczy MySQL (bez ścisłych ustawień ANSI). Wykorzystuje niestandardową konstrukcję:

SELECT key, value
FROM tableX
GROUP BY key ;

W najnowszej wersji (5.7 i 8.0+), w której rygorystyczne ustawienia ONLY_FULL_GROUP_BYsą domyślne, możesz użyć ANY_VALUE()funkcji dodanej w 5.7:

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

W przypadku innych DBMS, które mają funkcje okien (takie jak Postgres, SQL-Server, Oracle, DB2), możesz ich używać w ten sposób. Zaletą jest to, że możesz również wybrać inne kolumny w wyniku (oprócz keyi 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 ;

Dla starszych wersji powyższego i dla dowolnego innego DBMS, ogólny sposób, który działa prawie wszędzie. Wadą jest to, że nie można wybrać innych kolumn przy takim podejściu. Innym jest to, że funkcje agregujące, takie jak MIN()i MAX()nie działają z niektórymi typami danych w niektórych DBMS (takich jak bit, tekst, obiekty BLOB):

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

PostgreSQL ma specjalnego niestandardowego DISTINCT ONoperatora, z którego można także korzystać. Opcjonalne ORDER BYjest wybranie wiersza z każdej grupy:

SELECT DISTINCT ON (key) key, value
FROM tableX
-- ORDER BY key, <some_other_expressions> ;
ypercubeᵀᴹ
źródło
2
@WilliamKF Jeśli przez „wybrany arbitralnie” masz na myśli „wybrany losowo”, po prostu zastąp ORDER BY whateverzapytanie w ypercube wywołaniem funkcji losowej wyników.
Leigh Riffel,
1
@LeighRiffel To nie musi być przypadkowy, każdy wybór, tak prosty jak pierwszy napotkany działa dobrze.
WilliamKF,
3

W przypadku serwera 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

Podobnie, możesz mieć rownum = 2 dla drugiego zestawu wyników

JP Chauhan
źródło
2

Podobna do zaakceptowanej odpowiedzi, ale zamiast min () lub max () możesz użyć array_agg ()

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

Opcjonalnie możesz zamówić wartości wewnątrz tablicy, aby wybrać największą lub najmniejszą z nich:

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

(zaznaczone na PostgreSQL)

Alexkovelsky
źródło