Liste der E-Mails von Benutzern, die eine bestimmte Kategorie beobachten

Ich habe eine Data Explorer-Abfrage, die Folgendes ausführt:

SELECT * FROM category_users WHERE category_id = '10'

Das ergibt ein Ergebnis, das so aussieht:

Wie kann ich in dieser Ausgabe auch die E-Mail-Adressen der Benutzer anzeigen?

(Um Diskussionen über den Datenschutz vorwegzunehmen, möchte ich Folgendes anmerken: Wir nutzen ein privates Discourse für zahlende Mitglieder, die einzeln zugestimmt haben, dass wir ihre personenbezogenen Daten zur Erbringung von Dienstleistungen für sie verwenden. Wir nutzen Systeme, die nicht automatisiert miteinander kommunizieren, und verwenden E-Mails, um die Benutzer in zwei verschiedenen Systemen manuell zu verknüpfen.)

Sie müssen die Tabelle user_emails basierend auf der user_id aus der Tabelle category_users verbinden. Probieren Sie etwas wie Folgendes aus:

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

Vielen Dank, Simon, und entschuldige bitte, dass es so lange gedauert hat, dir zu antworten!

Ich habe deinen Befehl gerade ausprobiert, und er macht genau das, was ich wollte! :folded_hands:

Gibt es eine Möglichkeit, dieselben Daten siteweit zu erhalten und nicht nur für eine bestimmte Kategorie?

Ich frage deshalb, weil wir planen, unser Forum umzustrukturieren und feinere Kategorien zu verwenden. Das macht meinen Plan, für jede Kategorie eine separate Data-Explorer-Abfrage zu erstellen, weniger praktikabel.

Ich habe herausgefunden, wie man mehrere Kategorien abfragen kann, so etwas wie:

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

Aber ich müsste mich daran erinnern, die Abfrage nach einer Änderung der Kategorien zu aktualisieren, und das vergesse ich sehr gerne :smiley:

Sie können den Filter category_id = <number> einfach ganz entfernen, sodass die Abfrage etwa so aussieht:

SELECT
    cu.*,
    ue.email
FROM category_users cu
JOIN user_emails ue
  ON ue.user_id = cu.user_id
WHERE ue.primary = true

Der Data Explorer zeigt Ihnen die Kategorienaamen an, diese werden jedoch nicht beim Exportieren der Ergebnisse angezeigt. Falls dies für Sie ein Problem darstellt, können Sie den Kategorienaamen explizit als Spalte hinzufügen, zum Beispiel so:

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

Danke für die Frage, @simonk!

Ich verstehe nicht, warum du WHERE ue.primary = true anstelle von AND ue.primary = true verwendet hast. Ist eine WHERE-Klausel für die Abfrage immer erforderlich?

Nicht ganz. Es wäre vielleicht klarer, wenn wir @simons Abfrage leicht umformatieren:

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)

Die Bedingungen category_id und ue.primary gehören beide zum WHERE-Klausel und werden mit AND verknüpft. Wenn du eine der Bedingungen entfernst, lässt du das AND weg, behältst aber die WHERE-Klausel bei.

Die meisten einfachen SQL-Abfragen folgen diesem Muster:

SELECT <gewünschte_dinge>
FROM <tabellen>
WHERE <filterbedingungen>

Du kannst die WHERE-Klausel ganz weglassen, aber dann erhältst du jede Zeile aus den angegebenen Tabellen zurück.

Hier ist deine ursprüngliche Abfrage (umformatiert):

SELECT *
FROM category_users
WHERE category_id = '10'
  • SELECT *” bedeutet, dass die Abfrage alle Spalten aus allen beteiligten Tabellen zurückgeben soll.

  • FROM category_users” gibt die Tabelle an, die du abfragen möchtest. Die Tabelle category_users enthält Zeilen, die etwa so aussehen:

    id category_id user_id notification_level
    1 1 1 3
    2 1 2 3
    3 3 1 3

    category_id und user_id werden Fremdschlüssel genannt, da sie auf eine Zeile in einer anderen Tabelle verweisen (in diesem Fall die Tabellen categories und users). Die drei Zeilen oben bedeuten also, dass der Benutzer mit der ID 1 die Kategorien 1 und 3 verfolgt und der Benutzer mit der ID 2 die Kategorie 1 verfolgt. Das Feld notification_level gibt an, ob sie Verfolgen, Ersten Beitrag verfolgen oder Beobachten eingestellt haben.

  • WHERE category_id = '10'” bedeutet, dass du nur an Zeilen interessiert bist, in denen der Wert in der Spalte category_id gleich 10 ist. Ohne diese Zeile würdest du jede Zeile aus der Tabelle category_users erhalten.

@simon hat dir eine neue Version gegeben, die die E-Mail-Adresse des Benutzers hinzufügt:

Diese Abfrage hat aus zwei Gründen einige Änderungen gegenüber deiner ursprünglichen vorgenommen: E-Mail-Adressen werden in einer anderen Tabelle gespeichert (der Tabelle user_emails), und Benutzer können mehr als eine E-Mail-Adresse haben.

  • Im SELECT-Teil:

    • cu.*” bedeutet „alle Spalten aus der Tabelle cu"
    • ue.email” bedeutet „die Spalte email aus der Tabelle ue"
  • Im FROM-Teil:

    • Die Tabelle category_users hat jetzt einen Alias, „cu", was die Eingabe spart, wenn du mehrmals darauf Bezug nehmen musst.

    • Wir haben mit JOIN auf die Tabelle user_emails zugegriffen und ihr den Alias ue gegeben.

      Die Tabelle user_emails enthält Zeilen wie diese:

      id user_id email primary
      1 1 alex@example.com true
      2 1 alex@other.example.com false
      3 2 simon@example.com true

      Das bedeutet, dass der Benutzer mit der ID 1 zwei E-Mail-Adressen hat: alex@example.com (die primäre Adresse) und alex@other.example.com (eine sekundäre Adresse). Der Benutzer mit der ID 2 hat nur eine Adresse.

      Wenn du in SQL zwei Tabellen mit JOIN verbindest, musst du der Datenbank normalerweise mitteilen, was die Verknüpfungsbedingung ist. Wenn du das nicht tust, weiß die Datenbank nicht, welche Werte in den einzelnen Tabellen übereinstimmen sollen, und du erhältst jede mögliche Kombination von Zeilen aus den beiden Tabellen. Wenn du diese Abfrage schreiben würdest:

      SELECT *
      FROM category_users
      JOIN user_emails
      

      …würdest du mit den obigen Beispieldaten 9 Zeilen zurückbekommen: Du würdest die erste Zeile aus category_users dreimal erhalten, jeweils einmal mit jeder Zeile aus user_emails, dann ebenso die zweite Zeile aus category_users dreimal und schließlich die dritte Zeile aus category_users ebenfalls dreimal.

      Die Verknüpfungsbedingung teilt der Datenbank normalerweise mit, welche Spalte in den beiden Tabellen denselben Wert repräsentiert. In diesem Fall repräsentieren sowohl die Spalte category_users.user_id als auch die Spalte user_emails.user_id denselben Wert. Indem wir nach JOIN user_emails ue ON ue.user_id = cu.user_id schreiben, weisen wir die Datenbank an, die Zeilen aus user_emails den entsprechenden Zeilen aus category_users zuzuordnen.

    • Selbst mit der Verknüpfungsbedingung erhalten wir für den Benutzer mit der ID 1 immer noch 4 Zeilen zurück, da er 2 Kategorien verfolgt und 2 E-Mail-Adressen hat – wir erhalten eine Zeile für jede Kombination. Daher hat @simon eine zusätzliche Bedingung zur WHERE-Klausel hinzugefügt, damit die Abfrage nur Zeilen mit der primären E-Mail-Adresse des Benutzers zurückgibt. Diese Bedingung kommt zusätzlich zur bereits vorhandenen Bedingung hinzu (Einschränkung der Kategorie-ID) – damit Zeilen zurückgegeben werden, müssen sowohl category_id = '10' als auch ue.primary = true gelten.

Da du deine Suche nicht auf eine einzelne Kategorie einschränken wolltest, musstest du lediglich den Filter category_id entfernen. Du möchtest die gesamte WHERE-Klausel nicht entfernen, da du weiterhin nur primäre E-Mail-Adressen zurückgeben möchtest. Mit anderen Worten hat sich deine Filterbedingung von:

category_id = '10' AND ue.primary = true

zu

ue.primary = true

geändert.

Puh! Ich hoffe, das alles ergibt Sinn :nerd_face:

Vielen Dank für diesen unglaublich detaillierten Beitrag, @simonk! Ich muss zugeben, dass SQL für mich ein absolutes Rätsel war, und deine Erklärung hat mir wirklich geholfen, einen ersten Einblick zu bekommen. Ich schätze es sehr, dass du dir die Zeit genommen hast, mir zu helfen! :folded_hands: