我有一条 Data Explorer 查询语句,内容如下:
SELECT * FROM category_users WHERE category_id = '10'
该查询返回的结果如下所示:
如何在输出结果中同时显示用户的电子邮件地址?
(为避免引发隐私讨论,特此说明:我们使用的是面向付费会员的私有 Discourse 实例,这些会员已单独同意我们使用其个人信息以提供相关服务。由于我们使用的系统之间无法自动互通,因此我们通过电子邮件手动将两个不同系统中的用户进行关联。)
我有一条 Data Explorer 查询语句,内容如下:
SELECT * FROM category_users WHERE category_id = '10'
该查询返回的结果如下所示:
如何在输出结果中同时显示用户的电子邮件地址?
(为避免引发隐私讨论,特此说明:我们使用的是面向付费会员的私有 Discourse 实例,这些会员已单独同意我们使用其个人信息以提供相关服务。由于我们使用的系统之间无法自动互通,因此我们通过电子邮件手动将两个不同系统中的用户进行关联。)
您需要根据 category_users 表中的 user_id 连接 user_emails 表。请尝试以下方法:
SELECT
cu.*,
ue.email
FROM category_users cu
JOIN user_emails ue
ON ue.user_id = cu.user_id
WHERE category_id = '10'
AND ue.primary = true
谢谢,Simon,很抱歉回复晚了!
我刚刚尝试了你的查询,它完全符合我的预期!![]()
有没有办法获取全站相同的数据,而不仅仅是特定类别的?
我之所以这样问,是因为我们计划重组论坛,使用更细粒度的类别,这使得我为每个类别单独创建数据探索查询的计划变得不太可行。
我已经知道如何通过类似下面的方式请求多个类别:
WHERE (category_id = '48') OR (category_id = '66') OR (category_id = '57')
但我需要在更改类别后记得更新查询,而我很容易忘记这样做 ![]()
您可以直接移除 category_id = <number> 过滤条件,这样查询语句将类似于:
SELECT
cu.*,
ue.email
FROM category_users cu
JOIN user_emails ue
ON ue.user_id = cu.user_id
WHERE ue.primary = true
数据探索器会为您显示分类名称,但在导出结果时这些名称不会显示。如果这对您来说是个问题,您可以显式地将分类名称作为一列添加,类似于这样:
SELECT
c.name,
cu.*,
ue.email
FROM category_users cu
JOIN user_emails ue
ON ue.user_id = cu.user_id
JOIN categories c
ON cu.category_id = c.id
WHERE ue.primary = true
ORDER BY c.name
感谢你的提问 @simonk!
我不明白你为什么使用 WHERE ue.primary = true 而不是 AND ue.primary = true。查询是否总是需要 WHERE 子句?
不完全是。如果我们稍微重新格式化 @simon 的查询,可能会更清晰:
SELECT
cu.*,
ue.email
FROM category_users cu
JOIN user_emails ue ON ue.user_id = cu.user_id
WHERE (category_id = '10' AND ue.primary = true)
category_id 和 ue.primary 条件都是 WHERE 子句的一部分,通过 AND 连接。如果你移除其中一个条件,你需要移除 AND,但保留 WHERE 子句。
大多数简单的 SQL 查询遵循以下形式:
SELECT <你想要的东西>
FROM <表>
WHERE <过滤条件>
你可以完全省略 WHERE 子句,但那样你会从指定的表中获取每一行。
这是你原始的查询(重新格式化后):
SELECT *
FROM category_users
WHERE category_id = '10'
“SELECT *” 意味着你希望查询返回所有涉及表中的每一列。
“FROM category_users” 表示你想要查询的表。category_users 表包含类似这样的行:
| id | category_id | user_id | notification_level |
|---|---|---|---|
| 1 | 1 | 1 | 3 |
| 2 | 1 | 2 | 3 |
| 3 | 3 | 1 | 3 |
category_id 和 user_id 被称为外键,因为它们指向另一张表中的行(在本例中是 categories 和 users 表)。因此,上面的 3 行表示 id 为 1 的用户正在关注类别 1 和 3,而 id 为 2 的用户正在关注类别 1。notification_level 表示他们是处于关注、关注首帖还是追踪状态。
“WHERE category_id = '10'” 意味着你只对 category_id 列值为 10 的行感兴趣。如果没有这一行,你会从 category_users 表中获取每一行。
@simon 提供了一个新版本,添加了用户的电子邮件地址:
这个查询对你的原始查询做了一些修改,原因有两点:电子邮件地址存储在不同的表(user_emails 表)中,并且用户可以拥有多个电子邮件地址。
在 SELECT 子句中:
cu.*” 表示"cu 表的所有列”ue.email” 表示"ue 表的 email 列”在 FROM 子句中:
category_users 表现在有一个别名"cu",如果你需要多次引用它,可以节省一些输入。
我们已JOIN到 user_emails 表,并给它起了别名 ue。
user_emails 表包含类似这样的行:
| id | user_id | primary | |
|---|---|---|---|
| 1 | 1 | alex@example.com | true |
| 2 | 1 | alex@other.example.com | false |
| 3 | 2 | simon@example.com | true |
这意味着 id 为 1 的用户有两个电子邮件地址:alex@example.com(主地址)和 alex@other.example.com(次要地址)。id 为 2 的用户只有一个地址。
当你在 SQL 中 JOIN 两个表时,通常需要告诉数据库连接条件是什么。如果你不这样做,数据库就不知道每个表中的哪些值应该匹配,最终你会得到两个表中所有可能的行组合。如果你写了这个查询:
SELECT *
FROM category_users
JOIN user_emails
…使用上面的示例数据,你会得到 9 行:你会得到 category_users 的第一行三次,每次对应一个 user_emails 行;同样,你会得到 category_users 的第二行三次,最后得到 category_users 的第三行三次。
连接条件通常告诉数据库两个表中的哪一列代表相同的值。在本例中,category_users.user_id 列和 user_emails.user_id 列都代表相同的值。通过在 JOIN user_emails ue 之后编写 ON ue.user_id = cu.user_id,我们告诉数据库将 user_emails 行与相应的 category_users 行匹配。
即使有了 JOIN 条件,我们仍然会为 id 为 1 的用户返回 4 行,因为他们正在关注 2 个类别并且有 2 个电子邮件地址——我们会为每种组合返回一行。因此,@simon 在 WHERE 子句中添加了额外的条件,以便查询只返回用户主电子邮件地址的行。此条件是在已有条件(限制类别 ID)之外的——为了被返回,行必须满足 category_id = '10' 并且 ue.primary = true。
然后,因为你不想将搜索限制为单个类别,你只需要移除 category_id 过滤器。你不想移除整个 WHERE 子句,因为你仍然只想返回主电子邮件地址。换句话说,你的过滤条件从:
category_id = '10' AND ue.primary = true
变为
ue.primary = true
呼!希望这一切都讲得通 ![]()
感谢您如此详尽的帖子,@simonk!我必须承认,SQL 对我来说完全是一个谜,而您的解释对我开始理解它非常有帮助。非常感谢您抽出时间帮助我!![]()