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 cpi
coluna:
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.
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:
O acima me deu a tabela intermediária que eu precisava. Adicionando agrupamento e contagem, finalmente recebo os números que estou procurando:
Por fim, usando dois sub-SELECTs (um para 'I', outro para 'C'), compus uma consulta para obter as contagens por anúncio: