قائمة البريد الإلكتروني للمستخدمين الذين يتابعون فئة معينة

لدي استعلام في مستكشف البيانات ينفذ ما يلي:

SELECT * FROM category_users WHERE category_id = '10'

هذا يعطيني نتيجة تبدو كالتالي:

كيف يمكنني أيضًا عرض بريد المستخدمين الإلكتروني في هذا المخرجات؟

(لتجنب نقاشات الخصوصية، دعني أذكر ما يلي: نستخدم منصة Discourse خاصة للأعضاء المدفوعين، الذين أعطوا موافقتهم الفردية لاستخدام معلوماتهم الشخصية لغرض تقديم الخدمات لهم. لدينا أنظمة لا تتفاعل تلقائيًا مع بعضها البعض، ونستخدم البريد الإلكتروني لربط المستخدمين يدويًا بين النظامين المختلفين.)

تحتاج إلى دمج جدول user_emails بناءً على user_id من جدول category_users. جرب شيئًا مثل هذا:

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:

هل توجد طريقة للحصول على نفس البيانات على مستوى الموقع بأكمله، وليس فقط لفئة معينة؟

أسأل عن ذلك لأننا نخطط لإعادة هيكلة المنتدى الخاص بنا لاستخدام فئات أكثر تفصيلاً، مما يجعل خطتي لإنشاء استعلام منفصل لمكتشف البيانات لكل فئة أقل قابلية للتطبيق.

لقد تمكنت من معرفة كيفية طلب فئات متعددة باستخدام شيء مثل هذا:

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 هما جزء من جملة 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). إذن، الصفوف الثلاثة أعلاه تعني أن المستخدم ذو المعرف 1 يشاهد الفئتين 1 و 3، وأن المستخدم ذو المعرف 2 يشاهد الفئة 1. يشير notification_level إلى ما إذا كانوا يتابعون، يتابعون أول منشور، أو يتتبعون.

  • WHERE category_id = '10'” تعني أنك مهتم فقط بالصفوف التي تكون فيها القيمة في عمود category_id هي 10. بدون هذا السطر، ستحصل على كل صف من جدول category_users.

قدم لك @simon نسخة جديدة أضفت فيها عنوان البريد الإلكتروني للمستخدم:

أدخل هذا الاستعلام بعض التغييرات على استعلامك الأصلي لسببين: عناوين البريد الإلكتروني مخزنة في جدول مختلف (جدول user_emails)، ويمكن أن يكون للمستخدمين أكثر من عنوان بريد إلكتروني واحد.

  • في جملة SELECT:

    • cu.*” تعني “كل الأعمدة من جدول cu
    • ue.email” تعني “عمود email من جدول ue
  • في جملة FROM:

    • يحتوي جدول category_users الآن على اسم مستعار، وهو “cu”، مما يوفر بعض الكتابة إذا كنت بحاجة للإشارة إليه أكثر من مرة.

    • قمنا بـ JOIN مع جدول user_emails، وأعطيناه الاسم المستعار 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

      مما يعني أن المستخدم ذو المعرف 1 لديه عنوانان بريديان، alex@example.com (العنوان الأساسي) و alex@other.example.com (عنوان ثانوي). المستخدم ذو المعرف 2 لديه عنوان واحد فقط.

      عند إجراء JOIN بين جدولين في SQL، تحتاج عادةً إلى إخبار قاعدة البيانات بما هو شرط الربط. إذا لم تفعل ذلك، فإن قاعدة البيانات لن تعرف أي القيم في كل جدول يجب أن تتطابق، وبالتالي ستنتهي بنتيجة تحتوي على كل التوليفات الممكنة للصفوف في الجدولين. إذا كتبت هذا الاستعلام:

      SELECT *
      FROM category_users
      JOIN user_emails
      

      …مع البيانات أعلاه كمثال، ستحصل على 9 صفوف: ستحصل على الصف الأول من category_users ثلاث مرات، مرة مع كل صف من صفوف user_emails، وبالمثل ستحصل على الصف الثاني من category_users ثلاث مرات، وأخيرًا ستحصل على الصف الثالث من category_users ثلاث مرات.

      يخبر شرط الربط قاعدة البيانات عادةً أي عمود في الجدولين يمثل نفس القيمة. في هذه الحالة، يمثل عمود category_users.user_id وعمود user_emails.user_id نفس القيمة. بكتابة ON ue.user_id = cu.user_id بعد JOIN user_emails ue، نبلغ قاعدة البيانات بمطابقة صفوف user_emails مع صفوف category_users المناسبة.

    • حتى مع وجود شرط الربط، سنحصل على 4 صفوف للمستخدم ذي المعرف 1، لأنه يشاهد فئتين ولديه عنوانان بريديان - سنحصل على صف لكل توليفة. لذا، أضاف @simon شرطًا إضافيًا إلى جملة WHERE بحيث يعيد الاستعلام فقط الصفوف التي تحتوي على عنوان البريد الإلكتروني الأساسي للمستخدم. هذا الشرط بالإضافة إلى الشرط الموجود بالفعل (تقييد معرف الفئة) - لكي يتم إرجاع الصفوف، يجب أن يكون 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: