Lista de correos electrónicos de usuarios que ven una categoría específica

Tengo una consulta de Data Explorer que ejecuta lo siguiente:

SELECT * FROM category_users WHERE category_id = '10'

Esto me da un resultado que se ve así:

¿Cómo puedo también mostrar el correo electrónico de los usuarios en esta salida?

(Para evitar discusiones sobre privacidad, permítanme señalar lo siguiente: utilizamos un Discourse privado para miembros de pago, quienes han dado su consentimiento individual al uso de su información personal con el fin de brindarles servicios. Tenemos sistemas que no interoperan de forma automatizada y utilizamos correos electrónicos para conectar manualmente a los usuarios en dos sistemas diferentes.)

1 me gusta

Necesitas unir la tabla user_emails basándote en el user_id de la tabla category_users. Prueba algo como esto:

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
2 Me gusta

¡Gracias, Simon, y disculpa por haber tardado tanto en responderte!

Acabo de probar tu consulta y funciona exactamente como quería. :folded_hands:

¿Hay alguna manera de obtener los mismos datos en todo el sitio, no solo para una categoría específica?

Te lo pregunto porque estamos planeando reestructurar nuestro foro para usar categorías más granulares, lo que hace que mi plan de crear una consulta separada de Data Explorer para cada categoría sea menos viable.

He descubierto cómo solicitar varias categorías usando algo como esto:

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

Pero tendré que recordar actualizar la consulta después de cambiar las categorías, y es muy probable que se me olvide hacerlo :smiley:

1 me gusta

Puedes simplemente eliminar el filtro category_id = <number> por completo, de modo que la consulta se vería más o menos así:

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

El Explorador de Datos mostrará los nombres de las categorías por ti, pero no aparecerán al exportar los resultados. Si eso representa un problema para ti, puedes agregar explícitamente el nombre de la categoría como una columna, algo así:

SELECT
    c.name,
    cu.*,\n    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
3 Me gusta

¡Gracias por la consulta, @simonk!

No entiendo por qué usaste WHERE ue.primary = true en lugar de AND ue.primary = true. ¿La consulta siempre requiere un WHERE?

No exactamente. Sería más claro si reformateamos ligeramente la consulta de @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)

Las condiciones category_id y ue.primary son ambas parte de la cláusula WHERE, unidas con AND. Si eliminas una de las condiciones, quitas el AND, pero mantienes la cláusula WHERE.

La mayoría de las consultas SQL simples siguen esta forma:

SELECT <cosas_que_quieres>
FROM <tablas>
WHERE <condiciones_de_filtro>

Puedes omitir la cláusula WHERE por completo, pero entonces obtendrás todas las filas de las tablas que hayas especificado.

Aquí tienes tu consulta original (reformateada):

SELECT *
FROM category_users
WHERE category_id = '10'
  • SELECT *” significa que quieres que la consulta devuelva todas las columnas de todas las tablas involucradas.

  • FROM category_users” indica la tabla que quieres consultar. La tabla category_users contiene filas que se ven más o menos así:

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

    category_id y user_id se llaman claves foráneas porque apuntan a una fila en otra tabla (en este caso, las tablas categories y users). Por lo tanto, las 3 filas anteriores significan que el usuario con id 1 está vigilando las categorías 1 y 3, y el usuario con id 2 está vigilando la categoría 1. El notification_level indica si están Vigiando, Vigiando la primera publicación o Rastreando.

  • WHERE category_id = '10'” significa que solo te interesan las filas donde el valor en la columna category_id es 10. Sin esa línea, obtendrías todas las filas de la tabla category_users.

@simon te dio una nueva versión que añadía la dirección de correo electrónico del usuario:

Esta consulta realizó algunos cambios respecto a tu original por 2 razones: las direcciones de correo electrónico se almacenan en una tabla diferente (la tabla user_emails) y los usuarios pueden tener más de una dirección de correo electrónico.

  • En la cláusula SELECT:

    • cu.*” significa “todas las columnas de la tabla cu
    • ue.email” significa “la columna email de la tabla ue
  • En la cláusula FROM:

    • La tabla category_users ahora tiene un alias, “cu”, lo que ahorra escritura si necesitas referirte a ella más de una vez.

    • Hemos JOINeado a la tabla user_emails y le hemos dado el alias ue.

      La tabla user_emails contiene filas como esta:

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

      Lo que significa que el usuario con id 1 tiene 2 direcciones de correo electrónico, alex@example.com (la dirección principal) y alex@other.example.com (una dirección secundaria). El usuario con id 2 solo tiene una dirección.

      Cuando haces un JOIN de 2 tablas en SQL, normalmente necesitas decirle a la base de datos cuál es la condición de unión. Si no lo haces, la base de datos no sabe qué valores en cada una de las tablas deben coincidir, por lo que terminarás con todas las combinaciones posibles de filas en las 2 tablas. Si escribieras esta consulta:

      SELECT *
      FROM category_users
      JOIN user_emails
      

      …con los datos de ejemplo anteriores, obtendrías 9 filas: obtendrías la primera fila de category_users tres veces, una vez con cada una de las filas de user_emails, luego obtendrías de manera similar la segunda fila de category_users tres veces, y finalmente obtendrías la tercera fila de category_users tres veces.

      La condición de unión normalmente le dice a la base de datos qué columna en las 2 tablas representa el mismo valor. En este caso, la columna category_users.user_id y la columna user_emails.user_id ambas representan el mismo valor. Al escribir ON ue.user_id = cu.user_id después de JOIN user_emails ue, le decimos a la base de datos que empareje las filas de user_emails con las filas apropiadas de category_users.

    • Incluso con la condición de JOIN, todavía obtendremos 4 filas para el usuario con ID 1, porque está vigilando 2 categorías y tiene 2 direcciones de correo electrónico: obtendremos una fila para cada combinación. Así que @simon añadió una condición extra a la cláusula WHERE para que la consulta solo devolviera filas con la dirección de correo electrónico principal del usuario. Esta condición es además de la condición que ya existía (restringiendo el ID de la categoría): para que se devuelvan filas, estas deben tener category_id = '10' Y ue.primary = true.

Luego, como no querías restringir tu búsqueda a una sola categoría, solo necesitabas eliminar el filtro category_id. No quieres eliminar toda la cláusula WHERE, porque aún quieres devolver solo direcciones de correo electrónico principales. En otras palabras, tu condición de filtro cambió de:

category_id = '10' AND ue.primary = true

a

ue.primary = true

¡Uf! Espero que todo esto tenga sentido :nerd_face:

2 Me gusta

¡Gracias por el increíblemente detallado post, @simonk! Debo admitir que SQL es un misterio total para mí, y tu explicación fue realmente útil para empezar a entenderlo. ¡Agradezco mucho que hayas tomado el tiempo de ayudarme! :folded_hands:

1 me gusta

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.