私はこのようなテーブルを持っています:
Column | Type | Modifiers
---------+------+-----------
country | text |
food_id | int |
eaten | date |
そして、国ごとに、一番よく食べられる食べ物を手に入れたいと思っています。私が考えることができる最高のもの(私はpostgresを使用しています)は次のとおりです:
CREATE TEMP TABLE counts AS
SELECT country, food_id, count(*) as count FROM munch GROUP BY country, food_id;
CREATE TEMP TABLE max_counts AS
SELECT country, max(count) as max_count FROM counts GROUP BY country;
SELECT country, max(food_id) FROM counts
WHERE (country, count) IN (SELECT * from max_counts) GROUP BY country;
その最後のステートメントでは、2つの異なる食品の数が同じである関係を解消するためにGROUP BYとmax()が必要です。
これは、概念的に単純なものには多くの作業のように思えます。それを行うためのより簡単な方法はありますか?
PostgreSQLは、この質問が行われた翌年の8.4で ウィンドウ関数 のサポートを導入しました。今日、次のように解決される可能性があることに注意してください。
SELECT country, food_id
FROM (SELECT country, food_id, ROW_NUMBER() OVER (PARTITION BY country ORDER BY freq DESC) AS rn
FROM ( SELECT country, food_id, COUNT('x') AS freq
FROM country_foods
GROUP BY 1, 2) food_freq) ranked_food_req
WHERE rn = 1;
上記は引き分けになります。引き分けになりたくない場合は、代わりにDENSE_RANK()を使用できます。
今ではさらにシンプルになっています。PostgreSQL9.4ではmode()
関数が導入されました。
select mode() within group (order by food_id)
from munch
group by country
戻り値(user2247323の例のように):
country | mode
--------------
GB | 3
US | 1
こちらのドキュメントを参照してください: https://wiki.postgresql.org/wiki/Aggregate_Mode
https://www.postgresql.org/docs/current/static/functions-aggregate.html#FUNCTIONS-ORDEREDSET-TABLE
SELECT DISTINCT
"F1"."food",
"F1"."country"
FROM "foo" "F1"
WHERE
"F1"."food" =
(SELECT "food" FROM
(
SELECT "food", COUNT(*) AS "count"
FROM "foo" "F2"
WHERE "F2"."country" = "F1"."country"
GROUP BY "F2"."food"
ORDER BY "count" DESC
) AS "F5"
LIMIT 1
)
さて、急いで書いたのですが、よくチェックしていませんでした。副選択はかなり遅いかもしれませんが、これは私が考えることができる最も短くて最も単純なSQLステートメントです。酔っ払っていないときにもっと話そうと思います。
PS:そうですね、「foo」は私のテーブルの名前です。「food」には食べ物の名前が含まれ、「country」には国の名前が含まれています。サンプル出力:
food | country
-----------+------------
Bratwurst | Germany
Fisch | Frankreich
これを試して:
Select Country, Food_id
From Munch T1
Where Food_id=
(Select Food_id
from Munch T2
where T1.Country= T2.Country
group by Food_id
order by count(Food_id) desc
limit 1)
group by Country, Food_id
SELECT country, MAX( food_id )
FROM( SELECT m1.country, m1.food_id
FROM munch m1
INNER JOIN ( SELECT country
, food_id
, COUNT(*) as food_counts
FROM munch m2
GROUP BY country, food_id ) as m3
ON m1.country = m3.country
GROUP BY m1.country, m1.food_id
HAVING COUNT(*) / COUNT(DISTINCT m3.food_id) = MAX(food_counts) ) AS max_foods
GROUP BY country
MAX(。)GROUPBYが結びつきを断ち切るのは好きではありません...食べた日付を何らかの方法でJOINに組み込んで、最新のものを任意に選択する方法が必要です...
ライブデータで実行する場合、このクエリプランに興味があります。
select country,food_id, count(*) ne
from food f1
group by country,food_id
having count(*) = (select max(count(*))
from food f2
where country = f1.country
group by food_id)
一時テーブルなしでそれを行う方法は次のとおりです。
編集:簡略化
select nf.country, nf.food_id as most_frequent_food_id
from national_foods nf
group by country, food_id
having
(country,count(*)) in (
select country, max(cnt)
from
(
select country, food_id, count(*) as cnt
from national_foods nf1
group by country, food_id
)
group by country
having country = nf.country
)
このようなものを試してください
select country, food_id, count(*) cnt
into #tempTbl
from mytable
group by country, food_id
select country, food_id
from #tempTbl as x
where cnt =
(select max(cnt)
from mytable
where country=x.country
and food_id=x.food_id)
これはすべてを1つの選択にまとめることができますが、今はそれをいじくり回す時間がありません。
幸運を。
これが私があなたが望むものをあなたに与えると私が信じる声明であり、そして単純で簡潔です:
select distinct on (country) country, food_id
from munch
group by country, food_id
order by country, count(*) desc
ご意見をお聞かせください。
ところで、distinct on機能はPostgresでのみ利用可能です。
例、ソースデータ:
country | food_id | eaten
US 1 2017-1-1
US 1 2017-1-1
US 2 2017-1-1
US 3 2017-1-1
GB 3 2017-1-1
GB 3 2017-1-1
GB 2 2017-1-1
出力:
country | food_id
US 1
GB 3