# 每5个铜徽章获得一个银徽章

**URL:** <https://meta.discourse.org/t/a-silver-badge-for-each-5-bronze-badges/283284>\
**Category:** Data & reporting\
**Tags:** sql-triggered-badge\
**Created:** [2023年十月24日 15:33 UTC](https://meta.discourse.org/t/a-silver-badge-for-each-5-bronze-badges/283284 "2023-10-24T15:33:49Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![ganncamp](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ganncamp/32/106199_2.png) [@ganncamp](https://meta.discourse.org/u/ganncamp)\
**Post date:** [2023年十月24日 15:33 UTC](https://meta.discourse.org/t/a-silver-badge-for-each-5-bronze-badges/283284/1 "2023-10-24T15:33:49Z")

</div>

我们创建了一个铜牌徽章，[用户互助](https://community.sonarsource.com/badges/110/users-helping-users)，授予那些试图帮助其他用户的用户。该徽章是手动授予的（以便区分有帮助的尝试和“我也是”的回复）。

我们希望为_每_ 5 个铜牌徽章授予一个银牌徽章，[无价](https://community.sonarsource.com/badges/111/invaluable)。

我编写的 SQL 找到了正确的两个用户，但每个用户只找到一次：

```sql
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 个新的铜牌徽章。

是否有我搜索未找到的指南？

---

<div class="post-metadata">

**Author:** ![ganncamp](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ganncamp/32/106199_2.png) [@ganncamp](https://meta.discourse.org/u/ganncamp)\
**Post date:** [2023年十月26日 18:53 UTC](https://meta.discourse.org/t/a-silver-badge-for-each-5-bronze-badges/283284/2 "2023-10-26T18:53:50Z")

</div>

好的，更深入的搜索让我找到了一条线索，最终指向了[指南](https://meta.discourse.org/t/create-triggered-custom-badge-queries/19336)

回填（backfill）的事情仍然有点模糊，但我已经决定（显而易见地！）在我们的测试实例上试用这个。我猜回填是在夜间运行的，所以明天我会了解更多。

---

<div class="post-metadata">

**Author:** ![JammyDodger](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jammydodger/32/254611_2.png) [@JammyDodger](https://meta.discourse.org/u/JammyDodger)\
**Post date:** [2023年十月26日 19:08 UTC](https://meta.discourse.org/t/a-silver-badge-for-each-5-bronze-badges/283284/3 "2023-10-26T19:08:36Z")

</div>

> [@ganncamp](#):
>
> 另外，我还不清楚数学是如何实现的，这样我的两个用户每天都不会获得新的徽章（这将通过夜间触发器运行），即使他们没有获得 5 个新的铜徽章。

除非你勾选“可以多次授予”，否则即使他们第二次（或更多次）符合条件，它也只会被授予一次。👍

* * *

好的，我更仔细地阅读了你的帖子，我认为我对你想要实现的目标有了更清晰的认识。

根据当前的 SQL，即使你允许它被多次授予，这些用户也只会获得一次银徽章：

- 我已经在我的测试站点上创建了相关的徽章（包括允许多次授予）
- 授予了 5 个铜徽章并运行了后台作业以授予徽章（银徽章已成功授予 🥳）
- 然后我再次运行了 `BadgeGrant` 作业，但他们没有第二次获得银徽章
- 然后我将他们的铜徽章数量增加到 11 个，并再次运行了徽章授予作业
- 没有第二次授予银徽章

---

<div class="post-metadata">

**Author:** ![ganncamp](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ganncamp/32/106199_2.png) [@ganncamp](https://meta.discourse.org/u/ganncamp)\
**Post date:** [2023年十月27日 11:10 UTC](https://meta.discourse.org/t/a-silver-badge-for-each-5-bronze-badges/283284/4 "2023-10-27T11:10:21Z")

</div>

我检查了“多次”

 ![Selection_1402](https://global.discourse-cdn.com/meta/original/4X/f/1/0/f10f97b293d2d77303369a56d5b74b26bf0c5ac2.png)

但只授予了一次，尽管应该授予两次

 ![Selection_1404](https://global.discourse-cdn.com/meta/original/4X/f/2/c/f2c723f8ac9b0b707798a45fa3935257f3409b00.png)

---

<div class="post-metadata">

**Author:** ![ganncamp](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ganncamp/32/106199_2.png) [@ganncamp](https://meta.discourse.org/u/ganncamp)\
**Post date:** [2023年十月30日 17:45 UTC](https://meta.discourse.org/t/a-silver-badge-for-each-5-bronze-badges/283284/5 "2023-10-30T17:45:25Z")

</div>

那么……我该怎么做才能让我的用户获得他应得的 12 枚铜牌徽章和 2 枚银牌徽章？

---

<div class="post-metadata">

**Author:** ![JammyDodger](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jammydodger/32/254611_2.png) [@JammyDodger](https://meta.discourse.org/u/JammyDodger)\
**Post date:** [2023年十月30日 20:43 UTC](https://meta.discourse.org/t/a-silver-badge-for-each-5-bronze-badges/283284/6 "2023-10-30T20:43:07Z")

</div>

这是一个好问题，我一时半会儿不知道答案。🙂

我初步想到了使用 `RANK`，但我可能是在徒劳地挣扎……🤔

* * *

> **粗略原型...**
>
> ```sql
> 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`：

```sql
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` 作业运行时并没有多次授予。我不太确定为什么。🤔

我把自己搞糊涂了。我要去喝杯茶，重新整理一下思路。🙂

---

<div class="post-metadata">

**Author:** ![ganncamp](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ganncamp/32/106199_2.png) [@ganncamp](https://meta.discourse.org/u/ganncamp)\
**Post date:** [2023年十一月2日 12:54 UTC](https://meta.discourse.org/t/a-silver-badge-for-each-5-bronze-badges/283284/7 "2023-11-02T12:54:51Z")

</div>

嗯……昨天我又给了我的用户 4 个铜牌，看看隔夜运行是否至少能添加他刚刚“获得”的新徽章。（我想如果我不得不手动赶上其他人，我也可以。）但即使那样也没用。

 ![Selection_1418](https://global.discourse-cdn.com/meta/original/4X/7/0/8/708fde087e7df51a426e6496bec02780dd31a7a6.png)

---

<div class="post-metadata">

**Author:** ![tpetrov](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/tpetrov/32/164643_2.png) [@tpetrov](https://meta.discourse.org/u/tpetrov)\
**Post date:** [2023年十一月2日 13:48 UTC](https://meta.discourse.org/t/a-silver-badge-for-each-5-bronze-badges/283284/8 "2023-11-02T13:48:20Z")

</div>

我无法帮助您处理此查询，但建议您向 Discourse AI 机器人寻求帮助 - 选择顶部的机器人图标  
 ![image](https://global.discourse-cdn.com/meta/original/4X/5/a/4/5a4715068d236c3b6f2b2066ae1c3656d897a719.png) → GPT-4 → SQL Helper。

我发现它在根据我的需求创建数据浏览器查询方面非常出色，并且猜测它也可以帮助创建徽章查询。

---

<div class="post-metadata">

**Author:** ![JammyDodger](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jammydodger/32/254611_2.png) [@JammyDodger](https://meta.discourse.org/u/JammyDodger)\
**Post date:** [2023年十一月2日 14:08 UTC](https://meta.discourse.org/t/a-silver-badge-for-each-5-bronze-badges/283284/9 "2023-11-02T14:08:32Z")

</div>

不是每个人都有那个，Toni 🤫 你会让别人嫉妒的。🙂 （不过 @ganncamp 有，所以这是一个选项）

但是……我相当确定我的查询是正确的。它在预览中能正确挑选出用户，但在使用“每日更新”触发器时，它就不能授予多个徽章。

 ![02c298ac17213cbd4108be9f876f27493a8d0e61](https://global.discourse-cdn.com/meta/original/4X/8/b/2/8b2815ef2f3b42661bd2afe591750b41a10b136e.png)

我设置了另一个几乎相同的测试，基于“在特定主题中发帖5次”的徽章，使用“当用户创建或编辑帖子”的触发器——那个测试运行完美。我正在询问它们之间有什么区别……

这是用于比较的测试徽章的 SQL，如果有人能发现任何问题的话：

```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))

```

 ![image](https://global.discourse-cdn.com/meta/original/4X/0/6/c/06c0c5bd24b6727b81c4dd5bbff2daa056c46441.png)

---

<div class="post-metadata">

**Author:** ![ganncamp](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ganncamp/32/106199_2.png) [@ganncamp](https://meta.discourse.org/u/ganncamp)\
**Post date:** [2023年十一月2日 17:38 UTC](https://meta.discourse.org/t/a-silver-badge-for-each-5-bronze-badges/283284/10 "2023-11-02T17:38:07Z")

</div>

我能访问它 @tpetrov，但我的尝试……收效甚微。或者也许我只是擅长问难题？😆

---

<div class="post-metadata">

**Author:** ![JammyDodger](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jammydodger/32/254611_2.png) [@JammyDodger](https://meta.discourse.org/u/JammyDodger)\
**Post date:** [2023年十一月6日 10:44 UTC](https://meta.discourse.org/t/a-silver-badge-for-each-5-bronze-badges/283284/11 "2023-11-06T10:44:54Z")

</div>

> [@JammyDodger](#):
>
> 不过，经过进一步测试，这在预览中工作正常，但在实际的 `badge grant` 作业运行时不会被多次授予。我不太确定为什么。🤔

经过一番探索和咨询，似乎自动徽章授予器只会授予基于特定帖子的多个徽章。所以这类徽章只会授予第一个徽章（预览具有误导性 ☹）。

我认为在类似情况下，“升级”徽章效果很好（例如已解决的徽章）。所以例如，银牌授予 30 个，金牌授予 100 个，如果这可能是一个可行的替代方案？

---

<div class="post-metadata">

**Author:** ![ganncamp](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ganncamp/32/106199_2.png) [@ganncamp](https://meta.discourse.org/u/ganncamp)\
**Post date:** [2023年十一月6日 18:45 UTC](https://meta.discourse.org/t/a-silver-badge-for-each-5-bronze-badges/283284/12 "2023-11-06T18:45:33Z")

</div>

> [@JammyDodger](#):
>
> it seems that the auto badge granter will only award multiple badges if they’re based on specific posts

所以……即使铜牌是根据帖子授予的……那也不算，对吧？

> [@JammyDodger](#):
>
> I think in similar cases ‘escalating’ badges can work well (like the Solved ones). So a Silver for 30 and a Gold for 100, for instance, if that could be a viable alternative?

我不知道。我不认为我理解这个问题。 😆

我猜这个建议不是要找 5 个徽章，而是要找 5 个已授予徽章的帖子？我可以做到。在我“查找要授予徽章的新帖子”的报告中，我已经或多或少地完成了这项工作。

---

<div class="post-metadata">

**Author:** ![JammyDodger](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jammydodger/32/254611_2.png) [@JammyDodger](https://meta.discourse.org/u/JammyDodger)\
**Post date:** [2023年十一月6日 18:56 UTC](https://meta.discourse.org/t/a-silver-badge-for-each-5-bronze-badges/283284/13 "2023-11-06T18:56:34Z")

</div>

嗯。🤔 我觉得我明白你的意思了。让我再试试……

* * *

@ganncamp - 我认为我们可能取得了一些进展…… 🙂

根据铜徽章 A 的授予方式（通过帖子扳手或在 `/admin/users/{user_id}/{username}/badges` 页面提供理由）：

 ![post wrench](https://global.discourse-cdn.com/meta/original/4X/6/a/e/6aefde827f7282a42816cdab73df20b19cc839cb.png) ![/admin/users/user_id/username/badges](https://global.discourse-cdn.com/meta/original/4X/8/4/9/8496f83b7b90c599d954d030b043d1cb01cc910e.png)

那么我认为这是完全可能的。 🥳

```sql
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` 可以防止在没有人提供理由而授予徽章时出错，否则会失败）

 ![other badge settings](https://global.discourse-cdn.com/meta/original/4X/b/1/7/b17aac38b391f2c6e627d4489c3adaf7b8efbc2c.png)

我刚刚试了一下，通过触发 GrantBadge 后台作业来快进，我的测试用户终于获得了他们应得的全部荣誉。 🙂

 ![test_eight - first run](https://global.discourse-cdn.com/meta/original/4X/2/0/1/2014246d73b3d7cbaaf0bd8f2d7ebfde743a63ac.png)

然后我为他们授予了 5 个不同的帖子的另外 5 个铜徽章 A，并再次运行： 🎉

 ![image](https://global.discourse-cdn.com/meta/original/4X/1/2/4/1241f7a162323369558aea1e3df2f046f7763358.png)

---

<div class="post-metadata">

**Author:** ![ganncamp](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ganncamp/32/106199_2.png) [@ganncamp](https://meta.discourse.org/u/ganncamp)\
**Post date:** [2023年十一月7日 18:20 UTC](https://meta.discourse.org/t/a-silver-badge-for-each-5-bronze-badges/283284/14 "2023-11-07T18:20:59Z")

</div>

感谢 @JammyDodger！ 🎉 🎉 🎉

我已经在我自己的测试实例上设置好了（不是我不信任你 😂），希望这周就能投入生产！ 🤩

而且……是不是现在问一下，能否将你在此过程中学到的东西更新到[教程](https://meta.discourse.org/t/create-triggered-custom-badge-queries/19336?_sm_au_=iVVW4NJMtJZ2JjSF)中呢？ 😃

---

<div class="post-metadata">

**Author:** ![JammyDodger](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jammydodger/32/254611_2.png) [@JammyDodger](https://meta.discourse.org/u/JammyDodger)\
**Post date:** [2023年十一月7日 21:42 UTC](https://meta.discourse.org/t/a-silver-badge-for-each-5-bronze-badges/283284/15 "2023-11-07T21:42:47Z")

</div>

> [@ganncamp](#):
>
> （不是我不信任你 😂）

当然。信任但验证绝对是明智的选择。 🙂

> [@ganncamp](#):
>
> 而且……现在是问是否可以更新 [教程](https://meta.discourse.org/t/create-triggered-custom-badge-queries/19336?_sm_au_=iVVW4NJMtJZ2JjSF) 并加入你在这次任务中学到的东西的时候了吗？ 😃

我会看看是否能添加一点东西。 🙂 👍

---

<div class="post-metadata">

**Author:** ![ganncamp](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ganncamp/32/106199_2.png) [@ganncamp](https://meta.discourse.org/u/ganncamp)\
**Post date:** [2023年十一月8日 14:14 UTC](https://meta.discourse.org/t/a-silver-badge-for-each-5-bronze-badges/283284/16 "2023-11-08T14:14:14Z")

</div>

好吧……当作业在夜间运行时，  
我拥有 6 枚铜牌的用户获得了 1 枚银牌 ✅  
我拥有 13 枚铜牌的用户获得了…… 1 枚银牌 🙁

[教程中的这部分](https://meta.discourse.org/t/create-triggered-custom-badge-queries/19336?_sm_au_=iVVW4NJMtJZ2JjSF#)让我认为不需要单独的、明确的回填作业

> 由于每天都会运行完整的反向填充，无论如何都必须将其考虑在内，并包含对 `:backfill` 参数的处理。

对于已经获得超过 1 枚银牌的用户，我该如何让他们获得奖励？我必须手动操作吗？

---

<div class="post-metadata">

**Author:** ![JammyDodger](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jammydodger/32/254611_2.png) [@JammyDodger](https://meta.discourse.org/u/JammyDodger)\
**Post date:** [2023年十一月8日 14:22 UTC](https://meta.discourse.org/t/a-silver-badge-for-each-5-bronze-badges/283284/17 "2023-11-08T14:22:51Z")

</div>

回填是日常工作。“每日更新”触发器基本上就是这样，而其他触发器则更像是“即时”的（例如，如果一个徽章使用“当用户创建或编辑帖子时”的触发器，则无需等到第二天晚上即可授予）。

您能弹出徽章的截图给我看看有什么不同吗？

 ![badge b](https://global.discourse-cdn.com/meta/original/4X/d/c/7/dc7b3943233aaa725bb5ddbfd060724a8e3167d7.png)

---

<div class="post-metadata">

**Author:** ![ganncamp](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ganncamp/32/106199_2.png) [@ganncamp](https://meta.discourse.org/u/ganncamp)\
**Post date:** [2023年十一月8日 14:29 UTC](https://meta.discourse.org/t/a-silver-badge-for-each-5-bronze-badges/283284/18 "2023-11-08T14:29:11Z")

</div>

给你：

 ![Selection_1427](https://global.discourse-cdn.com/meta/original/4X/5/a/9/5a951d97057712c89b7ac03d39a9133fe3f533b1.png)

顺便说一句，我检查其中一些东西是因为……我不知道我在做什么 😂

---

<div class="post-metadata">

**Author:** ![JammyDodger](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jammydodger/32/254611_2.png) [@JammyDodger](https://meta.discourse.org/u/JammyDodger)\
**Post date:** [2023年十一月8日 14:38 UTC](https://meta.discourse.org/t/a-silver-badge-for-each-5-bronze-badges/283284/19 "2023-11-08T14:38:27Z")

</div>

您的用户“Badge A”拥有 13 个徽章，当您查看他们的 `/admin/users/{user_id}/{username}/badges` 页面时，原因已填写？

 ![/admin/users/{user_id}/{username}/badges](https://global.discourse-cdn.com/meta/original/4X/0/d/b/0db35cb3f2e5a3e893c58193c26edac4df62fde2.png)

> [@ganncamp](#):
>
> 顺便说一句，我检查其中一些事情是因为……我不知道我在做什么 😂

您已将重要的部分相同。 🙂 其他部分仍然是合法的，但可选。

您是在暂存站点还是在自托管测试站点上运行此程序？

---

<div class="post-metadata">

**Author:** ![ganncamp](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ganncamp/32/106199_2.png) [@ganncamp](https://meta.discourse.org/u/ganncamp)\
**Post date:** [2023年十一月8日 16:04 UTC](https://meta.discourse.org/t/a-silver-badge-for-each-5-bronze-badges/283284/20 "2023-11-08T16:04:01Z")

</div>

哇！谜团解开了！

 ![Selection_1428](https://global.discourse-cdn.com/meta/original/4X/f/8/6/f86a9e34cf1eaf8557685ac2c872cc343fd6b72e.png)

我曾以为这个任务是在（我的）凌晨运行的。

事实上，我最初是随意授予该用户徽章的，所以昨天我撤销了所有徽章，挖出了他之前的帖子并重新授予。任务在我授予徽章的过程中运行。

顺便说一句，这在我的暂存站点上。

我想第二个徽章将在几小时后授予，但我希望一次授予多个徽章。如果我撤销银徽章，这种情况会发生吗？他会在……2小时后获得2个新的银徽章吗？

[下一頁](https://meta.discourse.org/t/a-silver-badge-for-each-5-bronze-badges/283284.md?page=2)
