Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Soma os resultados de algumas consultas e, em seguida, encontre os 5 principais em SQL


Para UNION as linhas resultantes de todas as três consultas e, em seguida, escolha as 5 linhas com o maior amount :
(SELECT event_id, count(*) AS amount
FROM   pageview 
GROUP  BY event_id
ORDER  BY pageviews DESC, rand()
LIMIT  1000)

UNION ALL
(SELECT event_id, count(*)
FROM   upvote
GROUP  BY event_id
ORDER  BY upvotes DESC, rand()
LIMIT  1000)

UNION ALL
(SELECT event_id, count(*)
FROM   attending
GROUP  BY event_id
ORDER  BY attendants DESC, rand()
LIMIT  1000)

ORDER  BY 2 DESC
LIMIT  5;

O manual:

UNION ALL para manter duplicatas.

Para adicionar as contagens para cada event_id :
SELECT event_id, sum(amount) AS total
FROM (
   (SELECT event_id, count(*) AS amount
    FROM   pageview 
    GROUP  BY event_id
    ORDER  BY pageviews DESC, rand()
    LIMIT  1000)
    
    UNION ALL
    (SELECT event_id, count(*)
    FROM   upvote
    GROUP  BY event_id
    ORDER  BY upvotes DESC, rand()
    LIMIT  1000)
    
    UNION ALL
    (SELECT event_id, count(*)
    FROM   attending
    GROUP  BY event_id
    ORDER  BY attendants DESC, rand()
    LIMIT  1000)
    ) x
GROUP  BY 1
ORDER  BY sum(amount) DESC
LIMIT  5;

A parte complicada aqui é que nem todo event_id estará presente em todas as três consultas básicas. Portanto, tome cuidado para que um JOIN não perde linhas completamente e as adições não resultam em NULL .

Use UNION ALL , não UNION . Você não deseja remover linhas idênticas, deseja adicioná-las.

x é um alias de tabela e um atalho para AS x . É necessário para que uma subconsulta tenha um nome. Pode ser qualquer outro nome aqui.

O recurso SOL FULL OUTER JOIN não está implementado no MySQL (da última vez que verifiquei), então você precisa se contentar com UNION . FULL OUTER JOIN juntaria todas as três consultas básicas sem perder linhas.

Resposta à pergunta complementar

SELECT event_id, sum(amount) AS total
FROM (
   (SELECT event_id, count(*) / 100 AS amount
    FROM   pageview ... )
    
    UNION ALL
    (SELECT event_id, count(*) * 5 
    FROM   upvote ... )
    
    UNION ALL
    (SELECT event_id, count(*) * 10
    FROM   attending ... )
    ) x
GROUP  BY 1
ORDER  BY  sum(amount) DESC
LIMIT  5;

Ou, para usar as contagens de base de várias maneiras:
SELECT event_id
      ,sum(CASE source
              WHEN 'p' THEN amount / 100
              WHEN 'u' THEN amount * 5
              WHEN 'a' THEN amount * 10
              ELSE 0
           END)  AS total
FROM (
   (SELECT event_id, 'p'::text AS source, count(*) AS amount
    FROM   pageview ... )
    
    UNION ALL
    (SELECT event_id, 'u'::text, count(*)
    FROM   upvote ... )
    
    UNION ALL
    (SELECT event_id, 'a'::text, count(*)
    FROM   attending ... )
    ) x
GROUP  BY 1
ORDER  BY 2 DESC
LIMIT  5;