Obter maior valor comum para cada valor de outra coluna na SQL

votos
21

Eu tenho uma tabela como esta:

 Column  | Type | Modifiers 
---------+------+-----------
 country | text | 
 food_id | int  | 
 eaten   | date | 

E para cada país, eu quero pegar a comida que se come com mais freqüência. O melhor que posso pensar (estou usando 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;

Nesse último comunicado, o GROUP BY e max () são necessários para quebrar laços, onde dois alimentos diferentes têm a mesma contagem.

Este parece ser um monte de trabalho para algo conceitualmente simples. Existe uma maneira para a frente mais direto para fazê-lo?

Publicado 05/12/2008 em 18:58
fonte usuário
Em outras línguas...                            


9 respostas

votos
2

Tente algo parecido com isto

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)

Isso poderia ser colocar todos em uma única seleção, mas eu não tenho tempo para mexer com isso agora.

Boa sorte.

Respondeu 05/12/2008 em 19:17
fonte usuário

votos
3

Aqui está como fazê-lo sem quaisquer tabelas temporárias:

Edit: simplificado

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
                        )
Respondeu 05/12/2008 em 19:23
fonte usuário

votos
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
    )

Bem, eu escrevi este com pressa e não verificá-lo muito bem. O sub-select pode ser muito lento, mas este é mais curto e mais simples instrução SQL que eu poderia pensar. Eu provavelmente vou dizer mais quando estou menos bêbado.

PS: Oh, bem, "foo" é o nome da minha mesa, "alimento" contém o nome da comida e "country" o nome do país. Exemplo de saída:

   food    |  country   
-----------+------------
 Bratwurst | Germany
 Fisch     | Frankreich
Respondeu 05/12/2008 em 19:44
fonte usuário

votos
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

Eu não gosto do MAX (.) GROUP BY para quebrar laços ... Tem que haver uma maneira de incorporar data comido no Cadastre-se de alguma forma para selecionar arbitrariamente o mais recente ...

Estou interessado no plano de consulta para esta coisa se você executá-lo em seus dados ao vivo!

Respondeu 05/12/2008 em 21:50
fonte usuário

votos
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)  
Respondeu 05/12/2008 em 22:31
fonte usuário

votos
5

tente o seguinte:

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
Respondeu 06/12/2008 em 20:36
fonte usuário

votos
13

PostgreSQL introduziu suporte para funções de janelas em 8.4, um ano após esta pergunta foi feita. É importante notar que poderia ser resolvido hoje como segue:

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;

A descrição acima irá quebrar laços. Se você não quer quebrar laços, você poderia usar DENSE_RANK () em vez.

Respondeu 16/09/2012 em 18:17
fonte usuário

votos
1

Aqui está uma declaração que eu acredito que dá o que você quer e é simples e concisa:

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

Por favor, deixe-me saber o que você pensa.

BTW, a distinta em função só está disponível no Postgres.

Exemplo, os dados de fonte:

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

saída:

country | food_id
US        1
GB        3
Respondeu 13/04/2016 em 15:30
fonte usuário

votos
4

Agora é ainda mais simples: PostgreSQL 9.4 introduziu a mode()função:

select mode() within group (order by food_id)
from munch
group by country

retornos (como o exemplo de user2247323):

country | mode
--------------
GB      | 3
US      | 1

Consulte a documentação aqui: https://wiki.postgresql.org/wiki/Aggregate_Mode

https://www.postgresql.org/docs/current/static/functions-aggregate.html#FUNCTIONS-ORDEREDSET-TABLE

Respondeu 25/04/2017 em 14:40
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more