Verificando elegibilidade para o selo

Recebemos várias perguntas sobre a badge Aficionado (100 dias consecutivos). Geralmente, o problema é que um usuário perdeu um dia ou mais devido a diferenças nos fusos horários entre o fuso do usuário e o do servidor.

Sempre fiquei um pouco confuso com a consulta usada para conceder a badge. Acho que agora estou entendendo. Aqui está uma consulta do Data Explorer que usa uma lógica semelhante. Ela retorna os períodos de visitas consecutivas de um usuário. Retorna a data de início, a contagem de dias consecutivos e a data de término para cada período de visitas consecutivas. Por padrão, ela retorna todos os períodos com 10 ou mais visitas. Para descobrir quais dias um usuário perdeu, defina o parâmetro min_days como 1.

Se o valor period_end retornado na primeira linha dos resultados for a data atual em que você está executando a consulta, o usuário ainda está na disputa pela badge.

--[params]
-- string :username
-- int :min_days = 10

WITH consecutive_visits AS (
  SELECT user_id,
       visited_at,
       -- O valor de s será o mesmo para cada grupo de dias consecutivos
       visited_at - (DENSE_RANK() OVER (PARTITION BY user_id ORDER BY visited_at))::int s
    FROM user_visits
    WHERE user_id = (SELECT id FROM users WHERE username = :username)
)

SELECT
MIN(visited_at) period_start,
COUNT(*) AS consecutive_days,
MAX(visited_at) period_end
FROM consecutive_visits
GROUP BY user_id, s
HAVING COUNT(*) >= :min_days
ORDER BY period_start DESC