특정 카테고리를 시청 중인 사용자의 이메일 목록

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

시몬, 감사합니다. 그리고 이렇게 늦게 답장드려서 죄송합니다!

방금 쿼리를 시도해 봤는데, 제가 원하던 바로 그 동작을 합니다!:folded_hands:

특정 카테고리뿐만 아니라 사이트 전체에서 동일한 데이터를 가져올 수 있는 방법이 있을까요?

이렇게 묻는 이유는 포럼을 더 세분화된 카테고리로 재구성할 계획이 있어서, 각 카테고리에 대해 별도의 Data Explorer 쿼리를 만드는 제 계획이 점점 더 현실성이 없어지고 있기 때문입니다.

아래와 같은 방식으로 여러 카테고리를 요청하는 법은 알아냈습니다:

WHERE (category_id = '48') OR (category_id = '66') OR (category_id = '57')

하지만 카테고리를 변경할 때마다 쿼리를 업데이트해야 한다는 점을 기억해야 하는데, 저는 이런 걸 매우 자주 잊어버리는 편입니다 :smiley:

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

@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 조건은 모두 AND로 연결된 WHERE 절의 일부입니다. 조건 중 하나를 제거하면 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 테이블)의 행을 가리키기 때문에 **외래 키(foreign keys)**라고 불립니다. 따라서 위의 3개 행은 ID가 1인 사용자가 카테고리 1과 3을, ID가 2인 사용자가 카테고리 1을 보고 있다는 것을 의미합니다. notification_level은 사용자가 Watching(관심), Watching First Post(첫 게시물 관심) 또는 Tracking(추적) 상태인지 나타냅니다.

  • "WHERE category_id = '10'"은 category_id 컬럼의 값이 10인 행에만 관심이 있다는 의미입니다. 이 줄이 없다면 category_users 테이블의 모든 행을 받게 됩니다.

@simon님은 사용자의 이메일 주소를 추가한 새로운 버전을 제공했습니다:

이 쿼리는 원래 쿼리에서 몇 가지 변경 사항을 포함하고 있으며, 그 이유는 두 가지입니다: 이메일 주소는 다른 테이블(user_emails 테이블)에 저장되어 있고, 사용자는 여러 개의 이메일 주소를 가질 수 있기 때문입니다.

  • SELECT 절에서:

    • "cu.*"는 cu 테이블의 모든 컬럼을 의미합니다.
    • "ue.email"는 ue 테이블의 email 컬럼을 의미합니다.
  • FROM 절에서:

    • category_users 테이블에는 이제 별칭 "cu"가 부여되었습니다. 이는 테이블을 여러 번 참조해야 할 때 타이핑을 줄여줍니다.

    • user_emails 테이블과 JOIN을 수행했으며, 이 테이블에는 ue라는 별칭을 부여했습니다.

      user_emails 테이블에는 다음과 같은 행이 포함되어 있습니다:

      id user_id email 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할 때는 일반적으로 데이터베이스에 **조인 조건(join condition)**을 알려야 합니다. 그렇게 하지 않으면 데이터베이스가 각 테이블의 어떤 값이 서로 일치해야 하는지 알 수 없으므로, 두 테이블의 모든 가능한 행 조합이 생성됩니다. 다음과 같은 쿼리를 작성한다면:

      SELECT *
      FROM category_users
      JOIN user_emails
      

      …위 예시 데이터를 기준으로 9개의 행을 받게 됩니다: category_users의 첫 번째 행이 user_emails의 각 행과 매칭되어 3번 반환되고, 이어서 두 번째 category_users 행이 3번, 마지막으로 세 번째 category_users 행이 3번 반환됩니다.

      조인 조건은 일반적으로 두 테이블의 어떤 컬럼이 동일한 값을 나타내는지 데이터베이스에 알려줍니다. 이 경우 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

후다! 모두 이해가 되셨기를 바랍니다 :nerd_face:

@simonk님, 정말 상세하게 작성해 주셔서 감사합니다! 솔직히 SQL은 저에게 완전한 미스터리였는데, 설명 덕분에 이제 막 이해를 시작할 수 있었습니다. 이렇게 시간을 내어 도와주셔서 정말 감사드립니다! :folded_hands: