2009-10-22 22 views
6

Làm cách nào tôi có thể trả về cái gì có hiệu quả là một GROUP "liền kề" trong MySQL. Nói cách khác, một GROUP BY tôn trọng thứ tự của recordset?Làm thế nào tôi có thể làm một nhóm tiếp giáp bằng trong MySQL?

Ví dụ, SELECT MIN(col1), col2, COUNT(*) FROM table GROUP BY col2 ORDER BY col1 từ bảng sau đây col1 là một chỉ số yêu cầu duy nhất:

 
1 a 
2 a 
3 b 
4 b 
5 a 
6 a

lợi nhuận:

1 a 4 
3 b 2

nhưng tôi cần phải trở lại như sau:

1 a 2 
3 b 2 
5 a 2

Trả lời

5

Sử dụng:

SELECT MIN(t.id) 'mi', 
      t.val, 
      COUNT(*) 
    FROM (SELECT x.id, 
       x.val, 
       CASE 
        WHEN xt.val IS NULL OR xt.val != x.val THEN 
        @rownum := @rownum+1 
        ELSE 
        @rownum 
       END AS grp 
      FROM TABLE x 
      JOIN (SELECT @rownum := 0) r 
     LEFT JOIN (SELECT t.id +1 'id', 
         t.val 
        FROM TABLE t) xt ON xt.id = x.id) t 
GROUP BY t.val, t.grp 
ORDER BY mi 

Mấu chốt ở đây là tạo ra một giá trị nhân tạo sẽ cho phép nhóm.

Trước đây, điều chỉnh Guffa của câu trả lời:

SELECT t.id, t.val 
    FROM TABLE t 
LEFT JOIN TABLE t2 on t2.id + 1 = t.id 
    WHERE t2.val IS NULL 
     OR t.val <> t2.val 
+0

chuyển +1 sang bên phải, sau đó đặt -1. vì vậy nó sẽ không mang lại hiệu quả quét bảng. mysql không thể có chỉ mục trên biểu thức –

+0

Đó là nó! Cảm ơn nhiều! – Kuyenda

+0

Nếu bạn sử dụng 'CASE WHEN xt.id IS NULL HOẶC xt.val! = X.val' thì SQL sẽ không ngắt khi val là cố ý NULL, nhưng nó vẫn nắm bắt được phép so sánh offset đầu tiên. – Kuyenda

1

Nếu các số trong col1 tiếp giáp nhau, bạn có thể làm như sau:

select x.col1, x.col2 
from table x 
left join table y on x.col1 = y.col1 + 1 
where x.col2 <> isnull(y.col2, '') 

Nó hoạt động như thế này:

-x- -y- out 
1 a - - 1 a 
2 a 1 a 
3 b 2 a 3 b 
4 b 3 b 
5 a 4 b 5 a 
6 a 5 a 
+0

Như vậy, điều đó sẽ chỉ trả về 2 a, 4 b - xem câu trả lời của tôi để sửa chữa. –

+0

@rexem: Có, tôi đã căn chỉnh sai và so sánh với việc sửa lỗi cần thiết. – Guffa

0

này sẽ không làm việc:

SELECT min_col1 = MIN(col1), col2 
FROM table 
GROUP BY col2 
ORDER BY min_col1 

Có lẽ điều này?

SELECT min_col1, col2 
FROM (SELECT min_col1 = MIN(col1), col2 
     FROM table 
     GROUP BY col2) x 
ORDER BY min_col1 
+0

GROUP BY bỏ qua đơn đặt hàng. Tôi có hiệu quả cần nhóm theo chức năng tôn trọng thứ tự của recordset. – Kuyenda

+0

[Truy vấn đầu tiên hoạt động trong SQL Server.] –

1

cùng một logic như rexem, nhưng hoạt động trên bất kỳ RDBMS cửa sổ có khả năng (sẽ không hoạt động trên MySQL chưa):

CREATE TABLE tbl 
(
id INT, 
val VARCHAR(1) 
); 

INSERT INTO tbl(id,val) 
VALUES(1,'a'),(2,'a'),(3,'a'),(4,'a'),(5,'b'),(6,'b'),(7,'a'),(8,'a'),(9,'a'); 

nguồn:

1 a 
2 a 
3 a 
4 a 
5 b 
6 b 
7 a 
8 a 
9 a 

Truy vấn kiểu cửa sổ: (hoạt động trên cửa sổ-c rdbms apable):

WITH grouped_result AS 
(
    SELECT x.id, x.val, 
     COUNT(CASE WHEN y.val IS NULL OR y.val <> x.val THEN 1 END) 
     OVER (ORDER BY x.id) AS grp 
    FROM tbl x LEFT JOIN tbl y ON y.id + 1 = x.id 
) 

SELECT MIN(id) mi, val, COUNT(*) 
FROM grouped_result 
GROUP BY val, grp 
ORDER BY mi 

Output:

1 a 4 
5 b 2 
7 a 3 

BTW, đây là kết quả của sự grouped_result mà không GROUP BY:

1 a 1 
2 a 1 
3 a 1 
4 a 1 
5 b 2 
6 b 2 
7 a 3 
8 a 3 
9 a 3 

Feels viết lại tốt mysqlism-truy vấn để ANSI -conforming một :-) Bây giờ, trong khi mysql không có capabality windowing được nêu ra, rexem của câu trả lời là tốt nhất. Rexem, đó là một kỹ thuật mysql tốt (JOIN (SELECT @rownum: = 0)) ở đó, và afaik MSSQL và PostgreSQL không hỗ trợ ngầm khai báo biến, kudo! :-)

0

Here là mô tả dài hơn về giải pháp cơ bản giống như (tôi nghĩ) do omg-ponies cung cấp - "tạo giá trị nhân tạo cho phép nhóm".

0

Tôi biết câu hỏi này được hỏi hai năm rưỡi trước (và tôi không mong đợi bất kỳ vấn đề nào), nhưng tôi chỉ gặp phải vấn đề tương tự, ngoại trừ 'bảng' đã là một câu lệnh SQL rất phức tạp, vì vậy tôi không thể thực hiện bất kỳ tham gia nếu không copy-dán nó

Vì vậy, tôi đã có ý tưởng khác: trật tự bởi col2 và trừ đi số lượng hàng hiện tại với giá trị của col1

SELECT *, col1-(@rownum:[email protected]+1) FROM (SELECT * FROM table JOIN (SELECT @rownum:=0) AS i ORDER BY col2) AS t 

nào đưa ra một kết quả như thế này:

1 a 0 
2 a 0 
5 a 2 
6 a 2 
3 b -2 
4 b -2 

Bây giờ bạn chỉ cần nhóm theo giá trị của cột cuối cùng

SELECT MIN(col1) AS mi, col2, COUNT(*) FROM 
    (SELECT *, col1-(@rownum:[email protected]+1) AS grp FROM (SELECT * FROM table JOIN (SELECT @rownum:=0) AS i ORDER BY col2) AS t) AS x 
GROUP BY grp ORDER BY mi 
Các vấn đề liên quan