31

我有一张这样的桌子:

 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;

在最后一条语句中,需要 GROUP BY 和 max() 来打破关系,其中两种不同的食物具有相同的计数。

对于概念上简单的东西,这似乎需要做很多工作。有没有更直接的方法来做到这一点?

4

9 回答 9

22

现在更简单了:PostgreSQL 9.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

于 2017-04-25T14:40:13.223 回答
19

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() 代替。

于 2012-09-16T17:17:31.617 回答
8
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
于 2008-12-05T18:44:03.150 回答
6

尝试这个:

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
于 2008-12-06T19:36:27.787 回答
3
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)  
于 2008-12-05T21:31:29.490 回答
3

尝试这样的事情

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)

这可以全部放在一个选择中,但我现在没有时间处理它。

祝你好运。

于 2008-12-05T18:17:57.087 回答
3

以下是在没有任何临时表的情况下执行此操作的方法:

编辑:简化

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
                        )
于 2008-12-05T18:23:30.213 回答
3
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(.) GROUP BY 打破关系...必须有一种方法可以将吃过的日期以某种方式合并到 JOIN 中,以任意选择最近的一个...

如果您在实时数据上运行它,我对这个东西的查询计划很感兴趣!

于 2008-12-05T20:50:05.813 回答
3

这是一个声明,我相信它可以满足您的需求,并且简单明了:

select distinct on (country) country, food_id
from munch
group by country, food_id
order by country, count(*) desc

请让我知道你的想法。

顺便说一句,独特的功能仅在 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
于 2016-04-13T15:30:58.470 回答