MySQL chọn một cột DISTINCT, với các cột khác tương ứng


192
ID   FirstName   LastName
1      John        Doe
2      Bugs        Bunny
3      John        Johnson

Tôi muốn chọn DISTINCTkết quả từ FirstNamecột, nhưng tôi cần tương ứng IDLastName.

Tập kết quả chỉ cần hiển thị một John, nhưng với ID1 và một LastNameDoe.


1
Bạn muốn tên cuối cùng thuộc về ID thấp nhất có tên riêng biệt?
Thomas Langston

3
Logic nên đi vào lựa chọn của cái hàng đầu là gì? Tôi nghĩ bạn sẽ muốn cả John Doe và John Johnson xuất hiện vì họ là hai John khác biệt nhưng đó chỉ là tôi.
judda

4
DISTINCTkhông phải là một chức năng. Tất cả các câu trả lời với DISTINCT()đều sai. Lỗi sẽ hiển thị khi bạn không đặt nó sau SELECT.
Câu hỏi tràn vào

1
ALL câu trả lời sử dụng dấu ngoặc đơn sau từ phân biệt thực sự là sai. Khác biệt KHÔNG phải là một chức năng vì vậy nó không thể chấp nhận một tham số. Các dấu ngoặc đơn sau đây đơn giản được bỏ qua. Trừ khi bạn đang sử dụng PostgreSQL, trong đó các dấu ngoặc đơn sẽ tạo thành một "kiểu dữ liệu phức tạp"
Được sử dụng_By_Al yet 14/2/2016

Câu trả lời:


192

thử truy vấn này

 SELECT ID, FirstName, LastName FROM table GROUP BY(FirstName)

15
Làm thế nào để chúng ta biết hàng nào sẽ được trả lại?
William Entriken

26
@Full Decent bạn không thể, theo tài liệu của MySQL : "Máy chủ có thể tự do chọn bất kỳ giá trị nào từ mỗi nhóm, vì vậy trừ khi chúng giống nhau, các giá trị được chọn là không xác định.". Trong thực tế, tôi đã sử dụng thành công loại truy vấn này với mệnh đề ORDER BY, ví dụ: bạn có thể thêm ORDER BY id ASC / DESC và MySQL sẽ trả về kết quả nhất quán mỗi khi bạn thực hiện truy vấn. Nhưng tôi sẽ chắc chắn liệu có ai nên sử dụng các tính năng không có giấy tờ trong môi trường sản xuất hay không.
Arunas Junevicius

2
OP không đề cập đến phiên bản mysql.
diEcho

2
@sinaza xem câu trả lời cập nhật của tôi cho MySQL 5.7.5+để GROUP BYxử lý
fyrye

3
Điều này không hoạt động với chế độ only_full_group_by vì cả ID và LastName đều không được tổng hợp cũng không phải là một phần của chức năng nhóm. Cứu giúp!
ihodonald

63

Các DISTINCTtừ khóa không thực sự làm việc theo cách bạn đang mong nó đến. Khi bạn sử dụng, SELECT DISTINCT col1, col2, col3trên thực tế bạn đang chọn tất cả các bộ dữ liệu {col1, col2, col3} duy nhất.


14
Cảm ơn đã chỉ ra điều này Brian. Bạn có thể cung cấp một ví dụ về cách tôi có thể sử dụng NHÓM THEO để có được kết quả tương tự không?
ông

59

Để tránh các kết quả bất ngờ tiềm ẩn khi sử dụng GROUP BYmà không có hàm tổng hợp, như được sử dụng trong câu trả lời được chấp nhận , bởi vì MySQL có thể tự do lấy bất kỳ giá trị nào trong tập dữ liệu được nhóm khi không sử dụng hàm tổng hợp [sic] và các vấn đề với ONLY_FULL_GROUP_BY. Vui lòng xem xét sử dụng một tham gia loại trừ.

Loại trừ Tham gia - Các thực thể không rõ ràng

Giả sử tên và họ được lập chỉ mục duy nhất (không rõ ràng) , một cách khác GROUP BYlà sắp xếp bằng cách sử dụng một LEFT JOINbộ lọc kết quả, còn được gọi là THAM GIA loại trừ.

Xem Trình diễn

Thứ tự tăng dần (AZ)

Để lấy tên riêng biệt được đặt theo tên cuối cùng từ AZ

Truy vấn

SELECT t1.*
FROM table_name AS t1
LEFT JOIN table_name AS t2
ON t1.firstname = t2.firstname
AND t1.lastname > t2.lastname
WHERE t2.id IS NULL;

Kết quả

| id | firstname | lastname |
|----|-----------|----------|
|  2 |      Bugs |    Bunny |
|  1 |      John |      Doe |

Thứ tự giảm dần (ZA)

Để lấy tên riêng biệt được đặt theo tên cuối cùng từ ZA

Truy vấn

SELECT t1.*
FROM table_name AS t1
LEFT JOIN table_name AS t2
ON t1.firstname = t2.firstname
AND t1.lastname < t2.lastname
WHERE t2.id IS NULL;

Kết quả

| id | firstname | lastname |
|----|-----------|----------|
|  2 |      Bugs |    Bunny |
|  3 |      John |  Johnson |

Sau đó, bạn có thể đặt dữ liệu kết quả như mong muốn.


Tham gia loại trừ - Các thực thể mơ hồ

Nếu kết hợp tên và họ không phải là duy nhất (không rõ ràng) và bạn có nhiều hàng có cùng giá trị, bạn có thể lọc kết quả được đặt bằng cách bao gồm một điều kiện OR trên tiêu chí THAM GIA để lọc theo id.

Xem Trình diễn

dữ liệu tên_bảng

(1, 'John', 'Doe'),
(2, 'Bugs', 'Bunny'),
(3, 'John', 'Johnson'),
(4, 'John', 'Doe'),
(5, 'John', 'Johnson')

Truy vấn

SELECT t1.*
FROM table_name AS t1
LEFT JOIN table_name AS t2
ON t1.firstname = t2.firstname
AND (t1.lastname > t2.lastname
OR (t1.firstname = t1.firstname AND t1.lastname = t2.lastname AND t1.id > t2.id))
WHERE t2.id IS NULL;

Kết quả

| id | firstname | lastname |
|----|-----------|----------|
|  1 |      John |      Doe |
|  2 |      Bugs |    Bunny |

Đặt hàng Subquery

BIÊN TẬP

Câu trả lời ban đầu của tôi bằng cách sử dụng truy vấn con được đặt hàng , được viết trước MySQL 5.7.5 , không còn áp dụng được, do những thay đổi với ONLY_FULL_GROUP_BY. Vui lòng sử dụng các ví dụ tham gia loại trừ ở trên thay thế.

Nó cũng quan trọng cần lưu ý; khi ONLY_FULL_GROUP_BYbị vô hiệu hóa (hành vi ban đầu trước MySQL 5.7.5) , việc sử dụng GROUP BYkhông có hàm tổng hợp có thể mang lại kết quả không mong muốn, vì MySQL có thể tự do chọn BẤT K value giá trị nào trong tập dữ liệu được nhóm [sic] .

Có nghĩa là một IDhoặc lastnamegiá trị có thể được lấy mà không được liên kết với firstnamehàng được lấy .


CẢNH BÁO

Với MySQL GROUP BYcó thể không mang lại kết quả như mong đợi khi được sử dụng vớiORDER BY

Xem ví dụ trường hợp thử nghiệm

Phương pháp thực hiện tốt nhất, để đảm bảo kết quả mong đợi, là lọc phạm vi tập kết quả bằng cách sử dụng truy vấn con được đặt hàng.

dữ liệu tên_bảng

(1, 'John', 'Doe'),
(2, 'Bugs', 'Bunny'),
(3, 'John', 'Johnson')

Truy vấn

SELECT * FROM (
    SELECT * FROM table_name ORDER BY ID DESC
) AS t1
GROUP BY FirstName

Kết quả

| ID | first |    last |
|----|-------|---------|
|  2 |  Bugs |   Bunny |
|  3 |  John | Johnson |

So sánh

Để chứng minh kết quả bất ngờ khi sử dụng GROUP BYkết hợp vớiORDER BY

Truy vấn

SELECT * FROM table_name GROUP BY FirstName ORDER BY ID DESC

Kết quả

| ID | first |  last |
|----|-------|-------|
|  2 |  Bugs | Bunny |
|  1 |  John |   Doe |

3
Câu trả lời đầy đủ nhất cho đến nay. Thay đổi 'ID desc' thành 'ID asc' trong truy vấn đầu tiên cho phép chúng tôi truy xuất 'John Doe' hoặc 'John Johnson'. Thay đổi 'ID desc' trong truy vấn thứ hai sẽ không có hiệu ứng này.
carla

Trên postgres bạn cần ID trong nhóm bởi không chắc chắn về mysql.
Sachin Prasad

Liệu NHÓM THEO cột-A ĐẶT HÀNG theo cột-B trong một câu lệnh CHỌN luôn hoạt động chính xác với phiên bản mới nhất của MyriaDB?
Neal Davis

@NealDavis Theo hướng dẫn của MariaDBOrdering is done after grouping. , do đó, không phải trong trường hợp sử dụng này, ngoài ra MariaDB bỏ qua ORDER BY trong các truy vấn con (theo tiêu chuẩn SQL) mà không có a LIMIT. Bạn sẽ muốn sử dụng một Window FunctionĐể làm rõ hơn, bạn nên đặt câu hỏi của mình trong stackexchange của DBA , vì đây là một câu hỏi liên quan đến MySQL
fyrye

1
@NateS Không, GROUP BYcó thể chọn bất kỳ giá trị nào trong tập dữ liệu được nhóm, trừ khi một hàm tổng hợp được sử dụng trên các cột đó để buộc một giá trị cụ thể. Vì vậy, lastnamehoặc idcó thể đến từ bất kỳ hàng nào được đặt hàng. Ví dụ truy vấn con ban đầu được chấp nhận theo mặc định MySQL <= 5.7.4nhưng về mặt kỹ thuật vẫn gặp phải vấn đề này. Mặc dù điều ORDER BYnày giúp ngăn chặn một lựa chọn ngẫu nhiên, về mặt lý thuyết vẫn có thể, nhưng với xác suất ít hơn đáng kể so với việc không sử dụng ORDER BYtruy vấn con.
fyrye

23
SELECT ID,LastName 
From TABLE_NAME 
GROUP BY FirstName 
HAVING COUNT(*) >=1

2
thêm HAVINGlàm cho truy vấn của tôi chậm hơn 50%.
Butussy Butkus

Có trường hợp nào HAVING COUNT (*)> = 1 sẽ sai không?
Angelos Makrygiorgos


3

Làm thế nào về

`SELECT 
    my_distinct_column,
    max(col1),
    max(col2),
    max(col3)
    ...
 FROM
    my_table 
 GROUP BY 
    my_distinct_column`

2

Không chắc chắn nếu bạn có thể làm điều này với MySQL, nhưng bạn có thể sử dụng CTE trong T-SQL

; WITH tmpPeople AS (
 SELECT 
   DISTINCT(FirstName),
   MIN(Id)      
 FROM People
)
SELECT
 tP.Id,
 tP.FirstName,
 P.LastName
FROM tmpPeople tP
JOIN People P ON tP.Id = P.Id

Nếu không, bạn có thể phải sử dụng một bảng tạm thời.


1

Như được chỉ ra bởi fyrye , câu trả lời được chấp nhận liên quan đến các phiên bản cũ hơn của MySQL ONLY_FULL_GROUP_BYchưa được giới thiệu. Với MySQL 8.0.17 (được sử dụng trong ví dụ này), trừ khi bạn tắt, ONLY_FULL_GROUP_BYbạn sẽ nhận được thông báo lỗi sau:

mysql> SELECT id, firstName, lastName FROM table_name GROUP BY firstName;

LRI 1055 (42000): Biểu thức số 1 của danh sách CHỌN không có trong mệnh đề GROUP BY và chứa cột không phân chia 'mydatabase.table_name.id' không phụ thuộc chức năng vào các cột trong mệnh đề GROUP BY; cái này không tương thích với sql_mode = only_full_group_by

Một cách để giải quyết vấn đề này không được fyrye đề cập , nhưng được mô tả trong https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html , là áp dụng ANY_VALUE()chức năng này cho các cột không có trong GROUP BYmệnh đề ( idlastNametrong ví dụ này):

mysql> SELECT ANY_VALUE(id) as id, firstName, ANY_VALUE(lastName) as lastName FROM table_name GROUP BY firstName;
+----+-----------+----------+
| id | firstName | lastName |
+----+-----------+----------+
|  1 | John      | Doe      |
|  2 | Bugs      | Bunny    |
+----+-----------+----------+
2 rows in set (0.01 sec)

Như được viết trong các tài liệu nói trên,

Trong trường hợp này, MySQL bỏ qua tính không đặc trưng của các giá trị địa chỉ trong mỗi nhóm tên và chấp nhận truy vấn. Điều này có thể hữu ích nếu bạn đơn giản không quan tâm giá trị nào của cột không kết hợp được chọn cho mỗi nhóm. ANY_VALUE()không phải là hàm tổng hợp, không giống như các hàm như SUM()hoặc COUNT(). Nó chỉ đơn giản là hành động để ngăn chặn các thử nghiệm cho chủ nghĩa không điều trị.


Để làm rõ, tôi đặc biệt tránh đề xuất sử dụng ANY_VALUE()làm câu trả lời và nhận xét của tôi tập trung vào việc ngăn chặn các tập kết quả mơ hồ và không thể đoán trước. Vì như tên hàm gợi ý, nó có thể dẫn đến bất kỳ giá trị nào từ các hàng đã chọn được truy xuất. Tôi sẽ đề nghị sử dụng MAXhoặc MINthay vào đó.
fyrye

0

Hãy ghi nhớ khi sử dụng nhóm theo thứ tự và MySQL là cơ sở dữ liệu CHỈ cho phép các cột được sử dụng trong nhóm theo và / hoặc sắp xếp theo từng phần không phải là một phần của câu lệnh chọn.

Vì vậy, ví dụ: chọn cột1 từ nhóm bảng theo thứ tự cột2 theo cột3

Điều đó sẽ không bay trong các cơ sở dữ liệu khác như Postgres, Oracle, MSSQL, v.v. Bạn sẽ phải làm như sau trong các cơ sở dữ liệu đó

chọn cột1, cột2, cột3 từ nhóm bảng theo thứ tự cột2 theo cột3

Chỉ cần một số thông tin trong trường hợp bạn đã từng di chuyển mã hiện tại của mình sang cơ sở dữ liệu khác hoặc bắt đầu làm việc trong cơ sở dữ liệu khác và thử sử dụng lại mã.


-2

Bạn có thể sử dụng nhóm bằng cách hiển thị các giá trị riêng biệt và các trường tương ứng.

select * from tabel_name group by FirstName

Bây giờ bạn đã có đầu ra như thế này:

ID    FirstName     LastName
2     Bugs          Bunny
1     John          Doe


Nếu bạn muốn trả lời như

ID    FirstName     LastName
1     John          Doe
2     Bugs          Bunny

sau đó sử dụng truy vấn này

select * from table_name group by FirstName order by ID

2
Điều này sẽ không luôn mang lại kết quả như mong đợi khi nhóm theo thứ tự
fyrye

-3
SELECT DISTINCT(firstName), ID, LastName from tableName GROUP BY firstName

IMO đặt cược tốt nhất


32
Điều này sẽ không hoạt động, nó cũng sẽ đưa ID và họ vào đánh giá riêng biệt.
Ludo - Tắt kỷ lục

2
điều này giống như DISTINCT (FirstName, ID, LastName)
Tom Taylor

-4
SELECT DISTINCT (column1), column2
FROM table1
GROUP BY column1

1
DISTINCT()không phải là một chức năng. Ngoài ra DISTINCT và GROUP BY đang làm điều tương tự, vì vậy không có lý do nào đặt cả hai.
Marki555

Đây không phải là một tuyên bố hiệu quả, bạn nên sử dụng DISTINCT hoặc Group By không phải cả hai.
heshanlk
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.