Elenco delle email degli utenti che seguono una categoria specifica

Ho una query Data Explorer che esegue questo:

SELECT * FROM category_users WHERE category_id = '10'

Questo mi restituisce un risultato simile a questo:

Come posso visualizzare anche l’email degli utenti in questo output?

(Per prevenire discussioni sulla privacy, vorrei precisare quanto segue: utilizziamo un Discourse privato per i membri a pagamento, che hanno dato individualmente il consenso all’uso delle loro informazioni personali per fornire loro i servizi. Abbiamo sistemi che non interoperano in modo automatizzato e utilizziamo le email per collegare manualmente gli utenti in due sistemi diversi.)

Devi effettuare un JOIN sulla tabella user_emails basandoti sull’user_id della tabella category_users. Prova qualcosa di simile a questo:

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

Grazie, Simon, e scusa per averci messo tanto a risponderti!

Ho appena provato la tua query e fa esattamente quello che volevo! :folded_hands:

Esiste un modo per ottenere gli stessi dati per tutto il sito, non solo per una categoria specifica?

Te lo chiedo perché stiamo pianificando di ristrutturare il nostro forum utilizzando categorie più granulari, il che rende il mio piano di creare una query separata di Data Explorer per ogni categoria meno praticabile.

Ho capito come richiedere più categorie usando qualcosa del genere:

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

Ma dovrei ricordarmi di aggiornare la query dopo aver modificato le categorie, e sono molto propenso a dimenticarmelo :smiley:

Puoi semplicemente rimuovere del tutto il filtro category_id = <number>, così la query potrebbe apparire in questo modo:

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 visualizzerà i nomi delle categorie per te, ma non verranno mostrati quando esporti i risultati. Se questo rappresenta un problema, puoi aggiungere esplicitamente il nome della categoria come colonna, in questo modo:

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

Grazie per la domanda @simonk!

Non capisco perché hai usato WHERE ue.primary = true invece di AND ue.primary = true. La query richiede sempre una clausola WHERE?

Non esattamente. Potrebbe essere più chiaro se riformattiamo leggermente la query di @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)

Le condizioni category_id e ue.primary fanno entrambe parte della clausola WHERE, unite da AND. Se rimuovi una delle condizioni, rimuovi l’AND ma mantieni la clausola WHERE.

La maggior parte delle query SQL semplici segue questa forma:

SELECT <cose_che_vuoi>
FROM <tabelle>
WHERE <condizioni_di_filtro>

Puoi omettere completamente la clausola WHERE, ma in tal caso otterrai ogni riga dalle tabelle che hai specificato.

Ecco la tua query originale (riformattata):

SELECT *
FROM category_users
WHERE category_id = '10'
  • SELECT *” significa che vuoi che la query restituisca tutte le colonne da tutte le tabelle coinvolte.

  • FROM category_users” indica la tabella che vuoi interrogare. La tabella category_users contiene righe simili a queste:

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

    category_id e user_id sono chiamati chiavi esterne perché puntano a una riga in un’altra tabella (in questo caso, le tabelle categories e users). Quindi le 3 righe sopra significano che l’utente con id 1 sta monitorando le categorie 1 e 3, mentre l’utente con id 2 sta monitorando la categoria 1. Il campo notification_level indica se l’utente è in stato Watching, Watching First Post o Tracking.

  • WHERE category_id = '10'” significa che sei interessato solo alle righe in cui il valore nella colonna category_id è 10. Senza quella riga, otterresti ogni riga dalla tabella category_users.

@simon ti ha fornito una nuova versione che aggiunge l’indirizzo email dell’utente:

Questa query ha apportato alcune modifiche rispetto alla tua originale per due motivi: gli indirizzi email sono memorizzati in una tabella diversa (la tabella user_emails) e gli utenti possono avere più di un indirizzo email.

  • Nella clausola SELECT:

    • cu.*” significa “tutte le colonne dalla tabella cu
    • ue.email” significa “la colonna email dalla tabella ue
  • Nella clausola FROM:

    • La tabella category_users ora ha un alias, “cu”, che riduce la digitazione se devi farvi riferimento più volte.

    • Abbiamo fatto un JOIN alla tabella user_emails, assegnandole l’alias ue.

      La tabella user_emails contiene righe come queste:

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

      Il che significa che l’utente con id 1 ha 2 indirizzi email: alex@example.com (l’indirizzo principale) e alex@other.example.com (un indirizzo secondario). L’utente con id 2 ne ha solo uno.

      Quando esegui un JOIN di due tabelle in SQL, normalmente devi indicare al database qual è la condizione di join. Se non lo fai, il database non sa quali valori in ciascuna delle tabelle devono corrispondersi, quindi otterrai ogni possibile combinazione di righe tra le due tabelle. Se scrivessi questa query:

      SELECT *
      FROM category_users
      JOIN user_emails
      

      …con i dati di esempio sopra, otterresti 9 righe: otterresti la prima riga di category_users tre volte, una per ciascuna riga di user_emails, poi allo stesso modo otterresti la seconda riga di category_users tre volte, e infine otterresti la terza riga di category_users tre volte.

      La condizione di join indica normalmente al database quale colonna nelle due tabelle rappresenta lo stesso valore. In questo caso, la colonna category_users.user_id e la colonna user_emails.user_id rappresentano entrambe lo stesso valore. Scrivendo ON ue.user_id = cu.user_id dopo JOIN user_emails ue, diciamo al database di abbinare le righe di user_emails alle appropriate righe di category_users.

    • Anche con la condizione di JOIN, otterremo comunque 4 righe per l’utente con ID 1, perché sta monitorando 2 categorie e ha 2 indirizzi email: otterremo una riga per ogni combinazione. Quindi @simon ha aggiunto una condizione extra alla clausola WHERE in modo che la query restituisse solo le righe con l’indirizzo email principale dell’utente. Questa condizione è in aggiunta alla condizione già esistente (che limita l’ID della categoria): per essere restituite, le righe devono avere category_id = '10' E ue.primary = true.

Poi, poiché non volevi limitare la tua ricerca a una singola categoria, hai solo bisogno di rimuovere il filtro category_id. Non vuoi rimuovere l’intera clausola WHERE, perché vuoi comunque restituire solo gli indirizzi email principali. In altre parole, la tua condizione di filtro è cambiata da:

category_id = '10' AND ue.primary = true

a

ue.primary = true

Finito! Spero che tutto abbia senso :nerd_face:

Grazie per il post incredibilmente dettagliato, @simonk! Devo ammettere che SQL è un mistero completo per me, e la tua spiegazione è stata davvero utile per iniziare a capirlo. Apprezzo moltissimo il tempo che hai dedicato ad aiutarmi! :folded_hands: