Meu fórum não é muito grande, e a maioria das nossas reações de “like” vêm de “staff” (administradores, moderadores, TL=4). Eu queria ver como os likes de usuários regulares versus “staff” se comparavam, e listar o número de posts/dia para ter uma melhor noção do que está acontecendo e onde precisamos concentrar esforços para melhorar o uso das reações.
Eu e meu amigo ChatGPT criamos isto:
-- [params]
-- date :start_date = 2024-01-01
-- date :end_date = 2024-12-31
WITH date_range AS (
SELECT date_trunc('day', series) AS date
FROM generate_series(
:start_date::timestamp,
:end_date::timestamp,
'1 day'::interval
) series
),
staff_users AS (
SELECT id
FROM users
WHERE admin = true OR moderator = true OR trust_level = 4
)
SELECT
dr.date::date,
COALESCE(pa_non_staff.regular_likes_count, 0) AS regular_likes_count,
COALESCE(pa_staff.staff_likes_count, 0) AS staff_likes_count,
COALESCE(pa_non_staff.regular_likes_count, 0) + COALESCE(pa_staff.staff_likes_count, 0) AS total_likes,
COALESCE(posts_count.posts_per_day, 0) AS posts_per_day
FROM
date_range dr
LEFT JOIN (
SELECT
date_trunc('day', pa.created_at) AS action_date,
COUNT(*) AS regular_likes_count
FROM post_actions pa
WHERE pa.post_action_type_id = 2
AND pa.user_id NOT IN (SELECT id FROM staff_users)
AND pa.created_at >= :start_date
AND pa.created_at <= (:end_date::date + 1)
GROUP BY action_date
) pa_non_staff ON dr.date = pa_non_staff.action_date
LEFT JOIN (
SELECT
date_trunc('day', pa.created_at) AS action_date,
COUNT(*) AS staff_likes_count
FROM post_actions pa
WHERE pa.post_action_type_id = 2
AND pa.user_id IN (SELECT id FROM staff_users)
AND pa.created_at >= :start_date
AND pa.created_at <= (:end_date::date + 1)
GROUP BY action_date
) pa_staff ON dr.date = pa_staff.action_date
LEFT JOIN (
SELECT
date_trunc('day', p.created_at) AS post_date,
COUNT(*) AS posts_per_day
FROM posts p
WHERE p.created_at >= :start_date
AND p.created_at <= (:end_date::date + 1)
GROUP BY post_date
) posts_count ON dr.date = posts_count.post_date
ORDER BY dr.date
Alterações na consulta original de @SaraDev (obrigado, Sara!):
Resumo das Alterações no SQL
- Gerar Grupo de Staff:
Adicionada uma CTEstaff_userspara identificar usuários de staff a partir da tabelausers. Um usuário de staff é definido como qualquer um dos seguintes:
admin = truemoderator = truetrust_level = 4
- Separar Likes de Staff:
Adicionada uma subconsulta para calcular a contagem de likes de usuários de staff (staff_likes_count) filtrandopost_actionsparauser_idno grupostaff_users. - Renomear Coluna de Likes de Não-Staff:
Alterado o rótulo de saída para likes de não-staff delikes_countpararegular_likes_count. - Adicionar Total de Likes:
Introduzida uma colunatotal_likespara somarregular_likes_countestaff_likes_count. - Adicionar Posts por Dia:
Adicionada uma subconsulta para calcular o número de posts por dia (posts_per_day) e juntada ao intervalo de datas.
(Sim, o ChatGPT fez essa lista de alterações para mim também.)
Exemplo de resultados:
|data|regular_likes_count|staff_likes_count|posts_per_day|
|:—:|:—:|:—:|:—![]()
|1/1/24|0|6|7|
|1/2/24|0|5|3|
|1/3/24|1|0|4|
|1/4/24|1|2|5|
|1/5/24|9|9|30|
|1/6/24|0|1|11|
|1/7/24|2|4|11|
|1/8/24|0|5|18|
|1/9/24|0|0|2|
|1/10/24|0|0|7|
|1/11/24|0|4|5|
|1/12/24|4|0|4|
|1/13/24|6|0|10|
|1/14/24|1|7|18|
|1/15/24|2|4|7|\
Mesma consulta reportada por semanas para suavizar
-- [params]
-- integer :weeks_ago = 52
WITH date_range AS (
SELECT date_trunc('week', series) AS week_start
FROM generate_series(
date_trunc('week', now()) - (:weeks_ago || ' weeks')::interval,
date_trunc('week', now()),
'1 week'::interval
) series
),
staff_users AS (
SELECT id
FROM users
WHERE admin = true OR moderator = true OR trust_level = 4
)
SELECT
dr.week_start::date AS week_start,
COALESCE(pa_non_staff.regular_likes_count, 0) AS regular_likes_count,
COALESCE(pa_staff.staff_likes_count, 0) AS staff_likes_count,
COALESCE(pa_non_staff.regular_likes_count, 0) + COALESCE(pa_staff.staff_likes_count, 0) AS total_likes,
COALESCE(posts_count.posts_per_week, 0) AS posts_per_week
FROM
date_range dr
LEFT JOIN (
SELECT
date_trunc('week', pa.created_at) AS action_week,
COUNT(*) AS regular_likes_count
FROM post_actions pa
WHERE pa.post_action_type_id = 2
AND pa.user_id NOT IN (SELECT id FROM staff_users)
AND pa.created_at >= date_trunc('week', now()) - (:weeks_ago || ' weeks')::interval
AND pa.created_at <= date_trunc('week', now())
GROUP BY action_week
) pa_non_staff ON dr.week_start = pa_non_staff.action_week
LEFT JOIN (
SELECT
date_trunc('week', pa.created_at) AS action_week,
COUNT(*) AS staff_likes_count
FROM post_actions pa
WHERE pa.post_action_type_id = 2
AND pa.user_id IN (SELECT id FROM staff_users)
AND pa.created_at >= date_trunc('week', now()) - (:weeks_ago || ' weeks')::interval
AND pa.created_at <= date_trunc('week', now())
GROUP BY action_week
) pa_staff ON dr.week_start = pa_staff.action_week
LEFT JOIN (
SELECT
date_trunc('week', p.created_at) AS post_week,
COUNT(*) AS posts_per_week
FROM posts p
WHERE p.created_at >= date_trunc('week', now()) - (:weeks_ago || ' weeks')::interval
AND p.created_at <= date_trunc('week', now())
GROUP BY post_week
) posts_count ON dr.week_start = posts_count.post_week
ORDER BY dr.week_start
Caso seja interessante, aqui estão os prompts finais que modificaram a consulta de Sara:
Tenho uma consulta SQL que reporta a contagem diária de likes (likes_count) entre duas datas, mas preciso fazer as seguintes melhorias para produzir um resultado final que agregue dados por semanas e inclua detalhes adicionais:
- Definir um Grupo de Staff:
- Criar um grupo
staff_usersa partir da tabelausers. Um usuário deve ser considerado staff se atender a qualquer um dos seguintes critérios:admin = truemoderator = truetrust_level = 4
- Separar Likes por Staff e Não-Staff:
- Adicionar duas colunas separadas:
regular_likes_count: Contagem de likes de usuários não-staff.staff_likes_count: Contagem de likes de usuários staff.
- Garantir que a coluna
regular_likes_countexclua os likes gerados por usuários staff.
- Adicionar Total de Likes:
- Incluir uma coluna
total_likesque someregular_likes_countestaff_likes_count.
- Adicionar Posts por Período:
- Adicionar uma coluna
posts_per_weekque conte o número de posts criados durante cada semana.
- Agregar por Semanas:
- Modificar a consulta para agrupar todos os dados por intervalos semanais em vez de diários.
- Incluir uma coluna
week_startque represente a data de início de cada semana.
- Limitar por Semanas Atrás:
- Introduzir um parâmetro
:weeks_agopara limitar os resultados às últimas N semanas. O valor padrão deve ser 52 semanas (1 ano).
- Ordenar e Colunas Finais:
- Garantir que a saída seja ordenada por
week_starte inclua as seguintes colunas nesta ordem:week_start: A data de início da semana.regular_likes_count: A contagem de likes de usuários não-staff.staff_likes_count: A contagem de likes de usuários staff.total_likes: A soma deregular_likes_countestaff_likes_count.posts_per_week: O número de posts criados durante a semana.