Làm thế nào để chọn khác biệt cho một cột và bất kỳ trong một cột khác?


29

Tôi cần truy vấn cơ sở dữ liệu SQL để tìm tất cả các giá trị riêng biệt của một cột và tôi cần một giá trị tùy ý từ một cột khác. Ví dụ, hãy xem xét bảng sau với hai cột, khóa và giá trị:

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

Tôi muốn lấy lại một hàng mẫu, được chọn tùy ý, từ mỗi khóa riêng biệt, có thể nhận được ba hàng này:

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

Làm thế nào tôi có thể hình thành một truy vấn như vậy trong SQL?


2
DBMS nào (Oracle, SQL-Server, DB2, MySQL, Postgres)?
ypercubeᵀᴹ

1
Nó là một hệ thống độc quyền.
WilliamKF

Câu trả lời:


33

Truy vấn dễ nhất để viết là dành cho MySQL (với các cài đặt ANSI không nghiêm ngặt). Nó sử dụng cấu trúc phi tiêu chuẩn:

SELECT key, value
FROM tableX
GROUP BY key ;

Trong phiên bản gần đây (5.7 và 8.0+) trong đó các cài đặt nghiêm ngặt và ONLY_FULL_GROUP_BYlà mặc định, bạn có thể sử dụng ANY_VALUE()chức năng, được thêm vào 5.7:

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

Đối với các DBMS khác, có các chức năng cửa sổ (như Postgres, SQL-Server, Oracle, DB2), bạn có thể sử dụng chúng như thế này. Ưu điểm là bạn cũng có thể chọn các cột khác trong kết quả (bên cạnh keyvalue):

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 ;

Đối với các phiên bản cũ hơn ở trên và cho bất kỳ DBMS nào khác, một cách chung hoạt động gần như ở mọi nơi. Một nhược điểm là bạn không thể chọn các cột khác với phương pháp này. Một điều nữa là các hàm tổng hợp thích MIN()MAX()không hoạt động với một số kiểu dữ liệu trong một số DBMS (như bit, văn bản, đốm màu):

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

PostgreSQL có một DISTINCT ONtoán tử phi tiêu chuẩn đặc biệt cũng có thể được sử dụng. Tùy chọn ORDER BYlà để chọn hàng nào trong mỗi nhóm nên được chọn:

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

2
@WilliamKF Nếu bằng cách "chọn tùy ý", bạn có nghĩa là "được chọn ngẫu nhiên" thì chỉ cần thay thế ORDER BY whatevertruy vấn trong ypercube bằng một lệnh gọi đến hàm để ngẫu nhiên kết quả.
Leigh Riffel

1
@LeighRiffel Không cần phải ngẫu nhiên, bất kỳ sự lựa chọn nào, đơn giản như lần đầu tiên gặp phải đều hoạt động tốt.
WilliamKF

3

Đối với máy chủ 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

Tương tự như vậy, bạn có thể có rownum = 2 cho tập kết quả thứ hai của bạn


2

Tương tự như câu trả lời được chấp nhận, nhưng thay vì min () hoặc max (), bạn có thể sử dụng mảng_agg ()

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

Bạn có thể tùy ý sắp xếp các giá trị bên trong mảng để chọn lớn nhất hoặc nhỏ nhất trong số chúng:

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

(đã kiểm tra trên PostgreSQL)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.