I’ve been working on a small summary table that reads from the following:
create table page_event (
user_id uuid,
viewed_at timestamp,
type smallint,
product_id integer,
ad_id integer
);
And my query is quite simple:
select
type,
product_id,
count(*) as counts,
count(distinct user_id) as uniques
from
page_event
where
created_at >= '2023-09-01 14:17:00' and created_at < '2023-09-01 14:17:59'
group by
type,
product_id
However, this result gives me the event types separated. type
can be 0, 1, 2, 3, in fact it is an application-side enum. Currently, I’m aggregating that in application code and inserting into a summary table. It is pretty fast and that’s enough for the use case. However, I was wondering if it would be possible to do this in a single-query, so I could get the results of that select directly into the INSERT of my summary table.
I tried the following:
select
product_id,
sum(case when type = 0 then 1 else 0 end) as search,
sum(case when type = 1 then 1 else 0 end) as sidebar,
sum(case when type = 2 then 1 else 0 end) as pdp
from
page_event
where
created_at >= '2023-09-01 14:17:00' and created_at < '2023-09-01 14:17:59'
group by
product_id
But I can’t sum()
with distinct (user_id)
. This is how the summary table looks like:
create table event_summary (
created_at timestamp,
product_id integer,
ad_id integer,
search integer,
unique_search integer,
sidebar integer,
unique_sidebar integer,
pdp integer,
unique_pdp integer
);
create index on event_summary using BRIN (created_at);
2
Answers
If you need to count distinct users for each type then use
count()
combined withdistinct
:You may always use a FILTER clause for this purpose (not only for
count
, but also forcount distinct
Example