2009-09-10 52 views
7

Làm cách nào để nhận danh mục thường xuyên xảy ra nhất cho mỗi thẻ trong MySQL? Lý tưởng nhất, tôi sẽ muốn mô phỏng một hàm tổng hợp có thể tính toán mode của một cột.MySQL SELECT thường xuyên nhất theo nhóm

SELECT 
    t.tag 
    , s.category 
FROM tags t 
LEFT JOIN stuff s 
USING (id) 
ORDER BY tag; 

+------------------+----------+ 
| tag    | category | 
+------------------+----------+ 
| automotive  |  8 | 
| ba    |  8 | 
| bamboo   |  8 | 
| bamboo   |  8 | 
| bamboo   |  8 | 
| bamboo   |  8 | 
| bamboo   |  8 | 
| bamboo   |  10 | 
| bamboo   |  8 | 
| bamboo   |  9 | 
| bamboo   |  8 | 
| bamboo   |  10 | 
| bamboo   |  8 | 
| bamboo   |  9 | 
| bamboo   |  8 | 
| banana tree  |  8 | 
| banana tree  |  8 | 
| banana tree  |  8 | 
| banana tree  |  8 | 
| bath    |  9 | 
+-----------------------------+ 
+0

Chỉ cần nghĩ rằng tôi muốn đề cập đến một vài năm sau đó và thông minh hơn - không tổ chức thẻ như thế này, nó là một antipattern. Sử dụng bảng many2many để xác định mối quan hệ giữa các thẻ và các mục. Điều đó nói rằng, tôi vẫn muốn có một chức năng tổng hợp MODE trong MySQL. –

Trả lời

3
SELECT t1.* 
FROM (SELECT tag, category, COUNT(*) AS count 
     FROM tags INNER JOIN stuff USING (id) 
     GROUP BY tag, category) t1 
LEFT OUTER JOIN 
    (SELECT tag, category, COUNT(*) AS count 
     FROM tags INNER JOIN stuff USING (id) 
     GROUP BY tag, category) t2 
    ON (t1.tag = t2.tag AND (t1.count < t2.count 
     OR t1.count = t2.count AND t1.category < t2.category)) 
WHERE t2.tag IS NULL 
ORDER BY t1.count DESC; 

Tôi đồng ý đây là loại quá nhiều cho một truy vấn SQL đơn. Bất kỳ sử dụng của GROUP BY bên trong một subquery làm cho tôi wince. Bạn có thể làm cho nó trông đơn giản hơn bằng cách sử dụng quan điểm:

CREATE VIEW count_per_category AS 
    SELECT tag, category, COUNT(*) AS count 
    FROM tags INNER JOIN stuff USING (id) 
    GROUP BY tag, category; 

SELECT t1.* 
FROM count_per_category t1 
LEFT OUTER JOIN count_per_category t2 
    ON (t1.tag = t2.tag AND (t1.count < t2.count 
     OR t1.count = t2.count AND t1.category < t2.category)) 
WHERE t2.tag IS NULL 
ORDER BY t1.count DESC; 

Nhưng nó về cơ bản làm cùng một công việc đằng sau hậu trường.

Bạn nhận xét rằng bạn có thể thực hiện thao tác tương tự dễ dàng trong mã ứng dụng. Vậy tại sao bạn không làm điều đó? Thực hiện truy vấn đơn giản hơn để nhận số lượng cho mỗi danh mục:

SELECT tag, category, COUNT(*) AS count 
FROM tags INNER JOIN stuff USING (id) 
GROUP BY tag, category; 

Và sắp xếp kết quả trong mã ứng dụng.

+0

Tôi đã gặp khó khăn để làm điều đó để làm việc .. Nó sẽ có vẻ là tốt hơn để làm cho một chức năng tổng hợp MOST_FREQUENT() .. Tôi sẽ xem nếu đó là trong mức độ kỹ năng của tôi ở đây ... –

+0

Xin lỗi, tôi hiểu sai lược đồ của bạn. Tôi đã xem xét kỹ hơn và giả lập một cơ sở dữ liệu thử nghiệm để tôi có thể chắc chắn rằng truy vấn hoạt động. Thử phiên bản đã chỉnh sửa ở trên. –

+0

Điều đó dường như hoạt động. Đó là một chút khó khăn để nuốt mặc dù .. và có hai lựa chọn phụ thay vì chỉ một. Tôi ước rằng chỉ có một hàm tổng hợp được xây dựng MEAN() hoặc một cái gì đó :-P. Tôi có thể viết rằng sử dụng C trong 5 phút. –

2
SELECT tag, category 
FROM (
     SELECT @tag <> tag AS _new, 
       @tag := tag AS tag, 
       category, COUNT(*) AS cnt 
     FROM (
       SELECT @tag := '' 
       ) vars, 
       stuff 
     GROUP BY 
       tag, category 
     ORDER BY 
       tag, cnt DESC 
     ) q 
WHERE _new 

On dữ liệu của bạn, điều này sẽ trả về như sau:

'automotive', 8 
'ba',   8 
'bamboo',  8 
'bananatree', 8 
'bath',  9 

Đây là kịch bản thử nghiệm:

CREATE TABLE stuff (tag VARCHAR(20) NOT NULL, category INT NOT NULL); 

INSERT 
INTO stuff 
VALUES 
('automotive',8), 
('ba',8), 
('bamboo',8), 
('bamboo',8), 
('bamboo',8), 
('bamboo',8), 
('bamboo',8), 
('bamboo',10), 
('bamboo',8), 
('bamboo',9), 
('bamboo',8), 
('bamboo',10), 
('bamboo',8), 
('bamboo',9), 
('bamboo',8), 
('bananatree',8), 
('bananatree',8), 
('bananatree',8), 
('bananatree',8), 
('bath',9); 
3

(Edit: quên DESC trong BYs TRÌNH TỰ)

Dễ làm với LIMIT trong truy vấn phụ. Liệu MySQL vẫn có giới hạn không giới hạn trong truy vấn phụ không? Dưới đây là ví dụ sử dụng PostgreSQL.

=> select tag, (select category from stuff z where z.tag = s.tag group by tag, category order by count(*) DESC limit 1) AS category, (select count(*) from stuff z where z.tag = s.tag group by tag, category order by count(*) DESC limit 1) AS num_items from stuff s group by tag; 
    tag  | category | num_items 
------------+----------+----------- 
ba   |  8 |   1 
automotive |  8 |   1 
bananatree |  8 |   4 
bath  |  9 |   1 
bamboo  |  8 |   9 
(5 rows) 

Cột thứ ba chỉ cần thiết nếu bạn cần đếm.

1

này là dành cho những tình huống đơn giản:

SELECT action, COUNT(action) AS ActionCount FROM log GROUP BY action ORDER BY ActionCount DESC;

Các vấn đề liên quan