SELECT user_id, current_timestamp AS granted_at
FROM user_badges
WHERE badge_id = 110 -- Users Helping Users
AND (:backfill OR user_id IN (:user_ids))
GROUP BY user_id
HAVING COUNT(*) >= 5
제 SQL에 어떤 마법이 빠져 있는 건가요, 아니면 배수 처리가 SQL 외부에서 이루어지는 건가요?
또한, 두 사용자가 새로운 청동 배지를 5개 더 받지 않은 경우에도 매일 새로운 배지를 받지 않도록 수치가 어떻게 계산되는지 제게는 정말로 명확하지 않습니다(이것은 야간 트리거로 실행될 예정입니다).
WITH badge_count AS (
SELECT
user_id,
granted_at,
RANK() OVER (PARTITION BY user_id ORDER BY granted_at ASC) AS rank
FROM user_badges
WHERE badge_id = 110
)
SELECT user_id, granted_at
FROM badge_count
WHERE rank IN (5,10,15,20,25,30,35,40,45,50)
자, 이번에는 ROW_NUMBER를 대신 사용해 두 번째 시도를 해보겠습니다:
WITH badge_count AS (
SELECT
user_id,
granted_at,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY granted_at ASC) AS row
FROM user_badges
WHERE badge_id = 110
)
SELECT user_id, granted_at
FROM badge_count
WHERE row % 5 = 0
다만, 더 테스트를 해보니 미리보기에서는 올바르게 작동하지만 실제 badge grant 작업이 실행될 때 여러 번 부여되지 않는 문제가 있습니다. 그 이유는 잘 모르겠네요.
‘특정 주제에서 5개 게시물마다’ 배지 기준으로 ‘사용자가 게시물을 생성하거나 수정할 때’ 트리거를 사용해 거의 동일한 구성으로 테스트용 배지를 하나 더 만들어 봤는데, 그쪽은 완벽하게 작동해. 무엇이 다른지 알아보고 있는 중인데…
비교를 위해 그 테스트 배지의 SQL을 여기에 올릴게. 뭔가 보이는 사람이 있으면 알려줘:
WITH post_count AS (
SELECT
user_id,
id,
created_at,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at ASC) AS row
FROM posts
WHERE topic_id = 864
)
SELECT user_id, created_at granted_at, id post_id
FROM post_count
WHERE row % 5 = 0
AND (:backfill OR id IN (:post_ids))
WITH badge_count AS (
SELECT
user_id,
granted_at,
post_id,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY granted_at DESC) AS row
FROM user_badges
WHERE badge_id = 110
AND post_id IS NOT NULL
)
SELECT user_id, granted_at, post_id
FROM badge_count
WHERE row % 5 = 0
AND (:backfill OR post_id IN (:post_ids))
(AND post_id IS NOT NULL 조건을 추가하면 사유 없이 배지가 부여된 경우를 방지할 수 있으며, 그렇지 않으면 오류가 발생합니다)
백필(backfill)은 일일 작업입니다. ‘일일 업데이트’ 트리거는 기본적으로 바로 그 역할을 수행하는 반면, 다른 트리거들은 훨씬 더 '실시간’에 가깝습니다(예: 배지가 '사용자가 게시물을 생성하거나 편집할 때’라는 조건을 사용한다면, 상금이 지급되도록 하루 밤을 기다릴 필요가 없습니다).