Bagaimana cara memilih yang berbeda untuk satu kolom dan yang lainnya di kolom lain?

29

Saya perlu query database SQL untuk menemukan semua nilai yang berbeda dari satu kolom dan saya butuh nilai arbitrer dari kolom lain. Misalnya, perhatikan tabel berikut dengan dua kolom, kunci dan nilai:

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

Saya ingin mendapatkan kembali satu baris sampel, dipilih secara sewenang-wenang, dari setiap kunci yang berbeda, mungkin mendapatkan tiga baris ini:

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

Bagaimana saya bisa merumuskan permintaan seperti itu di SQL?

WilliamKF
sumber
2
DBMS (Oracle, SQL-Server, DB2, MySQL, Postgres) yang mana?
ypercubeᵀᴹ
1
Ini adalah sistem berpemilik.
WilliamKF

Jawaban:

33

Permintaan termudah untuk menulis adalah untuk MySQL (dengan pengaturan ANSI tidak ketat). Ini menggunakan konstruksi non-standar:

SELECT key, value
FROM tableX
GROUP BY key ;

Dalam versi terbaru (5.7 dan 8.0+) di mana pengaturan yang ketat dan ONLY_FULL_GROUP_BYdefault, Anda dapat menggunakan ANY_VALUE()fungsi, ditambahkan dalam 5.7:

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

Untuk DBMS lain, yang memiliki fungsi jendela (seperti Postgres, SQL-Server, Oracle, DB2), Anda dapat menggunakannya seperti ini. Keuntungannya adalah Anda dapat memilih kolom lain di hasilnya juga (selain keydan 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 ;

Untuk versi yang lebih lama di atas dan untuk DBMS lainnya, cara umum yang bekerja hampir di semua tempat. Salah satu kelemahannya adalah Anda tidak dapat memilih kolom lain dengan pendekatan ini. Lain adalah bahwa fungsi agregat suka MIN()dan MAX()tidak bekerja dengan beberapa tipe data di beberapa DBMS (seperti bit, teks, gumpalan):

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

PostgreSQL memiliki DISTINCT ONoperator non-standar khusus yang juga dapat digunakan. Opsional ORDER BYadalah untuk memilih baris mana dari setiap grup yang harus dipilih:

SELECT DISTINCT ON (key) key, value
FROM tableX
-- ORDER BY key, <some_other_expressions> ;
ypercubeᵀᴹ
sumber
2
@ WilliamKF Jika dengan "dipilih secara sewenang-wenang" yang Anda maksudkan "dipilih secara acak" maka cukup ganti permintaan ORDER BY whateverdi ypercube dengan panggilan ke fungsi untuk mengacak hasilnya.
Leigh Riffel
1
@LeighRiffel Tidak perlu acak, pilihan apa pun, sesederhana yang pertama kali ditemui berfungsi dengan baik.
WilliamKF
3

Untuk Server 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

Demikian juga, Anda bisa memiliki rownum = 2 untuk set hasil kedua Anda

JP Chauhan
sumber
2

Mirip dengan jawaban yang diterima, tetapi alih-alih min () atau maks () Anda dapat menggunakan array_agg ()

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

Anda dapat memesan nilai secara opsional di dalam array untuk memilih yang terbesar atau yang terkecil:

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

(dicentang pada PostgreSQL)

alexkovelsky
sumber