2009-09-10 14 views
7

MySQLの各タグで最も頻繁に発生するカテゴリを取得するにはどうすればよいですか?理想的には、列のmodeを計算する集計関数をシミュレートしたいと考えています。MySQLグループで最も頻繁に選択

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

はちょうど私が数年後に賢く言及しようと思いました - このようなタグを整理していない、それはアンチパターンです。タグとアイテムの関係を定義するには、many2manyテーブルを使用します。つまり、私はまだMySQLにMODE集約関数があることを望みます。 –

答えて

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; 

私は、これは一種のあまり、単一のSQLクエリのためであることに同意。サブクエリ内でGROUP BYを使用すると、私はうんざりします。

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; 

をしかし、それは基本的に舞台裏で同じ作業をやっている:あなたは、それはビューを使用して単純に見えるすることができます。

同様の操作をアプリケーションコードで簡単に行うことができます。どうしてそんなことをしないの?カテゴリごとのカウントを取得する簡単なクエリを実行します。

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

結果をアプリケーションコードで並べ替えます。あなたのデータに

+0

私はそれをうまく動作させることができませんでした。集約関数MOST_FREQUENT()を作成する方が良いようです。私のスキルレベル内にあるかどうかを確かめます... –

+0

申し訳ありません、私あなたのスキーマを誤解しました。私は詳細を見て、テストデータベースを嘲笑して、クエリが確実に動作するようにしました。上記の編集版をお試しください。 –

+0

それはうまくいくようです。しかし、それを飲み込むのはちょっと難しく、ちょうど1つではなく2つのサブ選択があります。私は、集計関数MEAN()または何か:-Pが組み込まれていればいいと思う。私はおそらく5分のようにCを使って書くことができます。 –

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 

、これは次の値を返します。

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

ここでテストスクリプトです:

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

(編集:ORDER BYSにDESCを忘れてしまった)

簡単には、サブクエリのLIMITを使用します。 MySQLには依然としてLIMIT-in-subqueriesの制限がありますか?以下の例では、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) 

第3列は、必要な場合にのみ必要です。

1

これは単純な状況にある。

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