2010-04-29 45 views
43

Trong C# nó sẽ là như thế này:Làm thế nào để chọn hàng đầu tiên cho mỗi nhóm trong MySQL?

table 
    .GroupBy(row => row.SomeColumn) 
    .Select(group => group 
     .OrderBy(row => row.AnotherColumn) 
     .First() 
    ) 

LINQ-to-SQL dịch nó vào mã T-SQL sau:

SELECT [t3].[AnotherColumn], [t3].[SomeColumn] 
FROM (
    SELECT [t0].[SomeColumn] 
    FROM [Table] AS [t0] 
    GROUP BY [t0].[SomeColumn] 
    ) AS [t1] 
OUTER APPLY (
    SELECT TOP (1) [t2].[AnotherColumn], [t2].[SomeColumn] 
    FROM [Table] AS [t2] 
    WHERE (([t1].[SomeColumn] IS NULL) AND ([t2].[SomeColumn] IS NULL)) 
     OR (([t1].[SomeColumn] IS NOT NULL) AND ([t2].[SomeColumn] IS NOT NULL) 
     AND ([t1].[SomeColumn] = [t2].[SomeColumn])) 
    ORDER BY [t2].[AnotherColumn] 
    ) AS [t3] 
ORDER BY [t3].[AnotherColumn] 

Nhưng nó không tương thích với MySQL.

+0

thể không bạn giám sát máy chủ DB để xem những gì các truy vấn C thực thi # (tôi một số công trình gì đoán rằng cú pháp của bạn ở trên là LINQ) – lexu

+0

@Iexu Có tôi có thể, và tôi đã làm nó với MS SQL Server. Nhưng tôi không có bất kỳ Linq-to-MySQL, chỉ có LINQ-To-Sql –

Trả lời

17

Khi tôi viết

SELECT AnotherColumn 
FROM Table 
GROUP BY SomeColumn 
; 

Nó hoạt động. IIRC trong RDBMS tuyên bố như vậy là không thể, bởi vì một cột mà không thuộc về khóa nhóm đang được tham chiếu mà không có bất kỳ loại tập hợp.

"Sự gian lận" này hoạt động rất gần với những gì tôi muốn. Vì vậy, tôi sử dụng nó để có được kết quả tôi muốn:

SELECT * FROM 
(
SELECT * FROM `table` 
ORDER BY AnotherColumn 
) t1 
GROUP BY SomeColumn 
; 
+0

Trong trường hợp tương tự, phần lựa chọn hoạt động cho tôi nhưng khi tôi cố gắng cập nhật kết quả thu được với truy vấn này trong mysql nó không hoạt động. Tôi đã thử nhiều giải pháp cho đến nay để "cập nhật" không thành công. Sẽ đánh giá cao bất kỳ trợ giúp/gợi ý ở đó. – user3445140

+3

Thảo luận về lý do tại sao câu lệnh đầu tiên hoạt động: http://stackoverflow.com/questions/1225144/why-does-mysql-allow-group-by-queries-without-aggregate-functions .Cần khởi động MySQL 5.7.5 điều này sẽ là bị tắt theo mặc định, http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_only_full_group_by –

60

Tôi chỉ dựa vào tiêu đề bài viết của bạn, vì tôi không biết C# và không hiểu truy vấn đã cho. Nhưng trong MySQL, tôi khuyên bạn nên thử các lựa chọn con. Trước tiên, hãy lấy một bộ khóa chính của các cột thú vị sau đó chọn dữ liệu từ các hàng đó:

SELECT somecolumn, anothercolumn 
    FROM sometable 
WHERE id IN (
       SELECT min(id) 
       FROM sometable 
       GROUP BY somecolumn 
      ); 
+0

Tôi nghĩ rằng nó sẽ làm việc cho tôi, nhưng giải pháp này yêu cầu tôi tạo một PK 'id' cho bảng của tôi. –

+0

Trong khi giải pháp C#/T-SQL không yêu cầu nó. –

+6

Vâng, thực hành tốt là luôn luôn có khóa chính và về mặt lý thuyết nếu bạn không có khóa chính, toàn bộ hàng phải là khóa chính của bạn (mặc dù MySQL sẽ chấp nhận một bảng không có khóa chính có hàng lặp lại). – lfagundes

5

Bạn nên sử dụng một số chức năng tổng hợp để lấy giá trị của một cột khác mà bạn muốn. Nghĩa là, nếu bạn muốn giá trị thấp nhất của AnotherColumn cho mỗi giá trị của SomeColumn (hoặc số lượng hoặc thứ tự từ điển), bạn có thể sử dụng:

SELECT SomeColumn, MIN(AnotherColumn) 
FROM YourTable 
GROUP BY SomeColumn 

Một số liên kết hy vọng hữu ích:

http://dev.mysql.com/doc/refman/5.1/en/group-by-functions.html

http://www.oreillynet.com/databases/blog/2007/05/debunking_group_by_myths.html

+0

Khi tôi làm điều đó, giá trị SomeColumn không nhất thiết phải là giá trị trong hàng nơi mà AnotherColumn = Min (AnotherColumn) –

+0

@Jader Dias: Như tôi đã nói trong câu trả lời của tôi, đó là lý do tại sao bạn cần PK! – lexu

+1

Min (AnotherColumn) trong ngữ cảnh nhóm là cột 1Column thấp nhất cho nhóm các hàng có cùng giá trị của SomeColumn, không phải cho tất cả các giá trị của cột khác cho toàn bộ bảng. –

12

Đây là một cách khác bạn có thể thử, không cần trường ID đó.

select some_column, min(another_column) 
    from i_have_a_table 
group by some_column 

Tuy nhiên tôi đồng ý với lfagundes mà bạn nên thêm một số khóa chính ..

Cũng hãy cẩn thận rằng bằng cách này, bạn có thể không (dễ dàng) lấy tại các giá trị khác là hàng giống như some_colum kết quả cặp another_column! Bạn sẽ cần lfagundes apprach và một PK để làm điều đó!

+0

điều này có ý nghĩa hơn cả! – Kefka

+0

Đó là giải pháp hoàn hảo cho tôi. – MeLight

0

Tuy nhiên, một cách khác để làm điều đó

Chọn tối đa từ nhóm làm việc trong quan điểm

SELECT * FROM action a 
WHERE NOT EXISTS (
    SELECT 1 FROM action a2 
    WHERE a2.user_id = a.user_id 
    AND a2.action_date > a.action_date 
    AND a2.action_type = a.action_type 
) 
AND a.action_type = "CF" 
-2

Tại sao không sử dụng MySQL LIMIT từ khóa?

SELECT [t2].[AnotherColumn], [t2].[SomeColumn] 
FROM [Table] AS [t2] 
WHERE (([t1].[SomeColumn] IS NULL) AND ([t2].[SomeColumn] IS NULL)) 
    OR (([t1].[SomeColumn] IS NOT NULL) AND ([t2].[SomeColumn] IS NOT NULL) 
    AND ([t1].[SomeColumn] = [t2].[SomeColumn])) 
ORDER BY [t2].[AnotherColumn] 
LIMIT 1 
+0

Điều này trả về hàng đầu tiên của * toàn bộ truy vấn *, không phải hàng đầu tiên của * mỗi nhóm *. Có * nên * là một cách để làm điều này cho mỗi nhóm, được đưa ra như thế nào phổ biến câu hỏi này, nhưng các nhóm SQL đã quá bận rộn tranh luận về ý nghĩa của NULL để làm phiền với các vấn đề thực tế như thế này. –

0

Làm thế nào về điều này:

SELECT SUBSTRING_INDEX(
     MIN(CONCAT(OrderColumn, '|', IFNULL(TargetColumn, '')) 
    ), '|', -1) as TargetColumn 
FROM table 
GROUP BY GroupColumn 
1

Từ MySQL 5.7 documentation

MySQL 5.7.5 và lên dụng cụ phát hiện sự phụ thuộc chức năng.Nếu chế độ SQL ONLY_FULL_GROUP_BY được bật (mặc định là mặc định), MySQL sẽ từ chối các truy vấn mà danh sách lựa chọn, điều kiện HAVING hoặc danh sách ORDER BY tham chiếu đến các cột không được phân tách không có tên trong mệnh đề GROUP BY. .

Điều này có nghĩa là giải pháp @Jader Dias sẽ không hoạt động ở mọi nơi.

Đây là một giải pháp mà sẽ làm việc khi ONLY_FULL_GROUP_BY được kích hoạt:

SET @row := NULL; 
SELECT 
    SomeColumn, 
    AnotherColumn 
FROM (
    SELECT 
     CASE @id <=> SomeColumn AND @row IS NOT NULL 
      WHEN TRUE THEN @row := @row+1 
      ELSE @row := 0 
     END AS rownum, 
     @id := SomeColumn AS SomeColumn, 
     AnotherColumn 
    FROM 
     SomeTable 
    ORDER BY 
     SomeColumn, -AnotherColumn DESC 
) _values 
WHERE rownum = 0 
ORDER BY SomeColumn; 
Các vấn đề liên quan