alehandrof
(Alex Armstrong)
2021 年 7 月 26 日午前 9:19
1
Data Explorer クエリで以下の処理を実行しています:
SELECT * FROM category_users WHERE category_id = '10'
これにより、以下のような結果が得られます:
この出力にユーザーのメールアドレスも表示するにはどうすればよいでしょうか?
(プライバシーに関する議論を未然に防ぐため、以下の点を明記しておきます。私たちは有料会員向けの非公開 Discourse を利用しており、会員はそれぞれ、サービス提供を目的とした個人情報利用に個別に同意しています。また、システム間には自動連携が機能していない部分があり、2 つの異なるシステム内のユーザーを手動で連携させるためにメールを利用しています。)
simon
2021 年 7 月 26 日午後 5:20
2
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
alehandrof
(Alex Armstrong)
2021 年 10 月 4 日午前 3:13
3
Simon さん、ありがとうございます!また、お返事が遅くなってしまい申し訳ありません。
早速ご提示いただいたクエリを試してみましたが、まさに私が求めていた通りの動作でした!
このデータを特定のカテゴリだけでなく、サイト全体で取得する方法はありますでしょうか?
この質問をした理由は、フォーラムの構造をより詳細なカテゴリに分けるように再編成する予定があるため、カテゴリごとに個別の Data Explorer クエリを作成するという私の計画が現実的ではなくなってきているからです。
複数のカテゴリを指定する方法は、以下のようにして解決できました。
WHERE (category_id = '48') OR (category_id = '66') OR (category_id = '57')
ただし、カテゴリを変更するたびにクエリを更新しなくてはならず、それを忘れてしまう可能性が高いのが悩みどころです
simonk
(Simon King)
2021 年 10 月 4 日午前 10:59
4
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
Data Explorer ではカテゴリ名が表示されますが、結果をエクスポートすると表示されません。これが問題となる場合は、カテゴリ名を明示的に列として追加できます。例えば以下のようにします。
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
alehandrof
(Alex Armstrong)
2021 年 10 月 5 日午前 9:46
5
@simonk さん、ご質問ありがとうございます!
なぜ WHERE ue.primary = true ではなく AND ue.primary = true を使われたのか、少しわかりません。クエリには常に WHERE 句が必要なのでしょうか?
simonk
(Simon King)
2021 年 10 月 5 日午後 5:45
6
正確にはそうではありません。@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 はユーザーのメールアドレスを追加した新しいバージョンを提供しました。
このクエリは元のクエリからいくつかの変更を加えていますが、その理由は 2 つあります。メールアドレスは別のテーブル(user_emails テーブル)に格納されており、ユーザーは複数のメールアドレスを持つ可能性があるためです。
SELECT 句では:
“cu.*” は「cu テーブルのすべての列」を意味します。
“ue.email” は「ue テーブルの email 列」を意味します。
FROM 句では:
category_users テーブルにはエイリアス “cu” が付与されており、複数回参照する必要がある場合に入力を節約できます。
user_emails テーブルに JOIN し、エイリアス ue を付けました。
user_emails テーブルには、以下のような行が含まれています。
つまり、ID 1 のユーザーは 2 つのメールアドレス(alex@example.com がプライマリ、alex@other.example.com がセカンダリ)を持っています。ID 2 のユーザーは 1 つのアドレスのみを持っています。
SQL で 2 つのテーブルを JOIN する場合、通常、データベースに結合条件 を指定する必要があります。これを指定しないと、データベースはどの値を一致させるべきか分からないため、2 つのテーブルのすべての可能な行の組み合わせが返されてしまいます。例えば、以下のクエリを書いたとします。
SELECT *
FROM category_users
JOIN user_emails
上記のサンプルデータを使用すると、9 行が返されます。category_users の最初の行が、user_emails の各行と組み合わされて 3 回返され、同様に 2 番目の行も 3 回、最後に 3 番目の行も 3 回返されます。
結合条件 は通常、2 つのテーブルのどの列が同じ値を表すかをデータベースに伝えます。この場合、category_users.user_id 列と user_emails.user_id 列は同じ値を表します。JOIN user_emails ue の後に ON ue.user_id = cu.user_id と記述することで、データベースに user_emails の行を適切な category_users の行と一致させるよう指示します。
結合条件があっても、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
お疲れ様でした!これで全てご理解いただけたでしょうか
alehandrof
(Alex Armstrong)
2021 年 10 月 11 日午後 12:05
7
@simonk さん、こんなに詳細な投稿をしてくださり、ありがとうございます!正直に言うと、SQL は私にとって完全に謎だったのですが、あなたの説明のおかげで理解を始めることができました。私のために時間を割いて助けていただき、本当に感謝しています!