AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 224127
Accepted
Parker
Parker
Asked: 2018-12-05 10:03:19 +0800 CST2018-12-05 10:03:19 +0800 CST 2018-12-05 10:03:19 +0800 CST

Contando e agrupando em vários OUTER JOINs

  • 772

Estou criando uma visualização de logs de anúncios (impressões, cliques e cliques por impressão). Eu tenho uma estrutura de tabela simples e algumas consultas de trabalho, mas estou tendo problemas para compô-las em uma única consulta que posso usar como uma visualização (não uma visualização materializada, pois serão dados em tempo real).

As tabelas são:

CREATE TABLE advert
(
  id integer NOT NULL PRIMARY KEY
);

CREATE TABLE advert_event
(
  code CHAR(1) NOT NULL PRIMARY KEY
);

CREATE TABLE advert_log
(
  advertisement integer NOT NULL REFERENCES advert(id),
  event_code CHAR(1) NOT NULL REFERENCES advert_event(code)
);

E alguns dados de exemplo que cobrem todos os casos possíveis:

INSERT INTO advert VALUES (1);
INSERT INTO advert VALUES (2);
INSERT INTO advert VALUES (3);
INSERT INTO advert VALUES (4);

INSERT INTO advert_event VALUES ('I'); -- Impression
INSERT INTO advert_event VALUES ('C'); -- Click

INSERT INTO advert_log VALUES (1, 'I');
INSERT INTO advert_log VALUES (1, 'C');
INSERT INTO advert_log VALUES (2, 'I');
INSERT INTO advert_log VALUES (2, 'I');
INSERT INTO advert_log VALUES (2, 'C');
INSERT INTO advert_log VALUES (3, 'I');
INSERT INTO advert_log VALUES (3, 'I');

Para referências, aqui está um conjunto das coisas que eu quero contar advert_log:

Consulta A.

SELECT * FROM advert,advert_event;

Resultado A.

 id | code
----+------
  1 | I
  1 | C
  2 | I
  2 | C
  3 | I
  3 | C
  4 | I
  4 | C
(8 rows)

Contagens de eventos por anúncio:

Consulta B.

SELECT DISTINCT advertisement,event_code,COUNT(*) OVER (PARTITION BY advertisement,event_code) FROM advert_log;

Resultado B.

 advertisement | event_code | count
---------------+------------+-------
             1 | I          |     1
             1 | C          |     1
             2 | I          |     2
             2 | C          |     1
             3 | I          |     1
(5 rows)

Para qualquer anúncio individual, as contagens corretas podem ser obtidas por consultas como:

Consulta C1.

SELECT COUNT(*) FROM advert_log WHERE advertisement=4 AND event_code='I';
 count
-------
     0
(1 row)

Consulta C2.

SELECT COUNT(*) FROM advert_log WHERE advertisement=4 AND event_code='C';
 count
-------
     0
(1 row)

Obviamente, minha consulta anterior exclui zero contagens, portanto, não detecta nenhum dos dois casos acima.

Em última análise, o que estou tentando fazer é transformar os números acima no seguinte, usando clicks(as entradas 'C') divididas por impressions(as entradas 'I') para derivar a cpicoluna:

 advertisement | impressions | clicks | cpi
---------------+-------------+--------+-----
             1 |           1 |     1  | 1.0
             2 |           2 |     1  | 0.5
             3 |           1 |     0  | 0.0
             4 |           0 |     0  | 0.0 <- or NULL, NaN, 1.0, ...

Minha abordagem inicial foi criar uma visão para as consultas C1 e C2 e chamar essa função de uma visão baseada na Consulta A.

Suspeito que exista uma maneira mais simples de atingir meu objetivo com uma única consulta.

postgresql join
  • 1 1 respostas
  • 446 Views

1 respostas

  • Voted
  1. Best Answer
    Parker
    2018-12-05T10:03:47+08:002018-12-05T10:03:47+08:00

    Consegui encontrar uma solução enquanto escrevia a pergunta, mas decidi postar a pergunta e a resposta, caso ajude alguém no futuro. Como alternativa, se alguém tiver uma solução mais simples ou com melhor desempenho para esse problema, ficarei feliz em ouvi-la.

    Consegui resolver meu problema de contagem de NULL usando um CROSS JOIN antes do OUTER JOIN:

    SELECT * FROM advert CROSS JOIN advert_event LEFT OUTER JOIN advert_log ON advert_log.advertisement=advert.id AND advert_log.event_code=advert_event.code;
    
     id | code | advertisement | event_code
    ----+------+---------------+------------
      1 | I    |             1 | I
      1 | C    |             1 | C
      2 | I    |             2 | I
      2 | I    |             2 | I
      2 | C    |             2 | C
      3 | I    |             3 | I
      3 | I    |             3 | I
      3 | C    |               |
      4 | I    |               |
      4 | C    |               |
    (10 rows)
    

    O acima me deu a tabela intermediária que eu precisava. Adicionando agrupamento e contagem, finalmente recebo os números que estou procurando:

    SELECT advert.id,advert_event.code,COUNT(advert_log.advertisement) FROM advert CROSS JOIN advert_event LEFT OUTER JOIN advert_log ON advert_log.advertisement=advert.id AND advert_log.event_code=advert_event.code GROUP BY advert.id,advert_event.code;
    
     id | code | count
    ----+------+-------
      1 | C    |     1
      1 | I    |     1
      2 | C    |     1
      2 | I    |     2
      3 | C    |     0
      3 | I    |     2
      4 | C    |     0
      4 | I    |     0
    (8 rows)
    

    Por fim, usando dois sub-SELECTs (um para 'I', outro para 'C'), compus uma consulta para obter as contagens por anúncio:

    CREATE VIEW advertisement_dashboard AS
    SELECT a.id,i.impressions,c.clicks,c.clicks::float/greatest(i.impressions, 1) AS cpi FROM advert a,
    (
      SELECT advert.id,COUNT(advert_log.advertisement) AS impressions FROM advert CROSS JOIN advert_event LEFT OUTER JOIN advert_log ON advert_log.advertisement=advert.id AND advert_log.event_code=advert_event.code
    GROUP BY advert.id,advert_event.code HAVING code='I'
    ) i,
    (
      SELECT advert.id,COUNT(advert_log.advertisement) AS clicks FROM advert CROSS JOIN advert_event LEFT OUTER JOIN advert_log ON advert_log.advertisement=advert.id AND advert_log.event_code=advert_event.code
    GROUP BY advert.id,advert_event.code HAVING code='C'
    ) c WHERE i.id=a.id AND c.id=a.id ORDER BY a.id ASC;
    
    SELECT * FROM advertisement_dashboard;
    
     id | impressions | clicks | cpi
    ----+-------------+--------+-----
      1 |           1 |      1 |   1
      2 |           2 |      1 | 0.5
      3 |           2 |      0 |   0
      4 |           0 |      0 |   0
    (4 rows)
    
    • 0

relate perguntas

  • Qual é a diferença entre um INNER JOIN e um OUTER JOIN?

  • Os procedimentos armazenados impedem a injeção de SQL?

  • Como é a saída de uma instrução JOIN?

  • Sequências Biológicas do UniProt no PostgreSQL

  • Qual é a diferença entre a replicação do PostgreSQL 9.0 e o Slony-I?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve