تقرير لوحة البيانات - الإعجابات

هذا هو إصدار SQL لتقرير لوحة المعلومات للإعجابات.

يوفر هذا الاستعلام تقريرًا عن العدد الإجمالي للإعجابات التي تم تقديمها لجميع المنشورات على موقع ما، يومًا بعد يوم، ضمن نطاق تاريخ محدد.

-- [params]
-- date :start_date = 2023-12-08
-- date :end_date = 2024-01-10

WITH date_range AS (
  SELECT date_trunc('day', series) AS date
  FROM generate_series(
    :start_date::timestamp,
    :end_date::timestamp,
    '1 day'::interval
  ) series
)

SELECT
  dr.date::date,
  COALESCE(pa.likes_count, 0) AS likes_count
FROM
  date_range dr
LEFT JOIN (
  SELECT
    date_trunc('day', pa.created_at) AS action_date,
    COUNT(*) AS likes_count
  FROM post_actions pa
  WHERE pa.post_action_type_id = 2
    AND pa.created_at >= :start_date
    AND pa.created_at <= (:end_date::date + 1)
  GROUP BY action_date
) pa ON dr.date = pa.action_date
ORDER BY dr.date

شرح استعلام SQL

يعتمد الهيكل الرئيسي للاستعلام على تعبير جدول مشترك (CTE) يسمى date_range، والذي يُستخدم لإنشاء سلسلة من الطوابع الزمنية، يمثل كل منها يومًا مختلفًا ضمن الفترة المحددة من قبل المستخدم.

المعلمات

يقبل الاستعلام معلمتين:

  • :start_date: بداية الفترة التي سيتم إنشاء التقرير لها.
  • :end_date: نهاية الفترة التي سيتم إنشاء التقرير لها.

التعبير الجدول المشترك: date_range

  • generate_series هي دالة تنشئ مجموعة من الطوابع الزمنية من :start_date إلى :end_date، بزيادة فاصل زمني قدره ‘1 يوم’.
  • date_trunc('day', series) يقتطع الطابع الزمني إلى بداية اليوم، مما يؤدي فعليًا إلى تطبيع جميع الطوابع الزمنية إلى 00:00:00 من أيامها المعنية.
  • النتيجة هي مجموعة من التواريخ، تاريخ واحد لكل صف، تغطي النطاق الكامل من :start_date إلى :end_date.

الاستعلام الفرعي: عد الإعجابات

يُستخدم استعلام فرعي لحساب عدد الإعجابات لكل يوم عن طريق عد الصفوف من جدول post_actions.

  • يقوم هذا الاستعلام بتصفية post_actions للإدخالات التي يشير فيها نوع الإجراء إلى إعجاب (حيث يعني post_action_type_id = 2 ‘إعجاب’).
  • يقوم بتصفية الإجراءات حسب النطاق الزمني، مضيفًا يومًا واحدًا إلى تاريخ النهاية لتضمين الإعجابات المقدمة في اليوم الأخير.
  • يقوم بتجميع النتائج حسب اليوم وحساب الإعجابات لكل يوم.

الاستعلام الرئيسي: دمج النتائج

يقوم القسم الأخير من الاستعلام بدمج مجموعة جميع التواريخ من CTE date_range مع عدد الإعجابات من الاستعلام الفرعي.

  • يضمن LEFT JOIN تضمين جميع التواريخ من date_range في النتيجة، حتى لو لم تكن هناك إجراءات إعجاب مقابلة لتاريخ معين (لم يتم العثور على عمليات ربط في الاستعلام الفرعي).
  • يُستخدم COALESCE لاستبدال العدم (NULL) (من الأيام التي لا توجد بها إعجابات) بالصفر، مما يضمن أن التقرير يعكس بدقة الأيام التي لا يوجد بها أي نشاط إعجاب.
  • يتم ترتيب مجموعة النتائج النهائية حسب التاريخ لتوفير عرض زمني للإعجابات المقدمة خلال الفترة المحددة.

نتائج مثال

date likes_count
2023-12-08 123
2023-12-09 156
2023-12-10 278
2023-12-11 134
2023-12-12 89
إعجابَين (2)

هل يحتاج هذا إلى AND pa.deleted_at IS NULL لتصفية الإعجابات التي تم إلقاؤها ثم إزالتها لتتوافق، أم أن هذا سيكون تغييرًا محتملاً في استعلام لوحة المعلومات نفسه؟

إعجابَين (2)

حاليًا، يتضمن تقرير لوحة المعلومات الإعجابات المحذوفة، لذا فإن إضافة AND pa.deleted IS NULL سيغير كيفية تطابق هذا الاستعلام مع تقرير لوحة المعلومات.

قد يكون تعديل تقرير لوحة المعلومات الأساسي لعدم تضمين الإعجابات المحذوفة تغييرًا جيدًا يجب مراعاته.

إعجابَين (2)

ليس لدي منتديات كبيرة، ومعظم ردود الفعل التي نحصل عليها تأتي من “الموظفين” (المسؤولون، المشرفون، المستوى 4). أردت أن أرى كيف تقارن الإعجابات من المستخدمين العاديين مقابل “الموظفين”، وأن أسرد عدد المشاركات/اليوم للحصول على فهم أفضل لما يحدث وأين نحتاج إلى تركيز الجهود لتحسين استخدام ردود الفعل.

أنا وصديقي ChatGPT توصلنا إلى هذا:

-- [params]
-- date :start_date = 2024-01-01
-- date :end_date = 2024-12-31

WITH date_range AS (
  SELECT date_trunc('day', series) AS date
  FROM generate_series(
    :start_date::timestamp,
    :end_date::timestamp,
    '1 day'::interval
  ) series
),
staff_users AS (
  SELECT id
  FROM users
  WHERE admin = true OR moderator = true OR trust_level = 4
)

SELECT
  dr.date::date,
  COALESCE(pa_non_staff.regular_likes_count, 0) AS regular_likes_count,
  COALESCE(pa_staff.staff_likes_count, 0) AS staff_likes_count,
  COALESCE(pa_non_staff.regular_likes_count, 0) + COALESCE(pa_staff.staff_likes_count, 0) AS total_likes,
  COALESCE(posts_count.posts_per_day, 0) AS posts_per_day
FROM
  date_range dr
LEFT JOIN (
  SELECT
    date_trunc('day', pa.created_at) AS action_date,
    COUNT(*) AS regular_likes_count
  FROM post_actions pa
  WHERE pa.post_action_type_id = 2
    AND pa.user_id NOT IN (SELECT id FROM staff_users)
    AND pa.created_at >= :start_date
    AND pa.created_at <= (:end_date::date + 1)
  GROUP BY action_date
) pa_non_staff ON dr.date = pa_non_staff.action_date
LEFT JOIN (
  SELECT
    date_trunc('day', pa.created_at) AS action_date,
    COUNT(*) AS staff_likes_count
  FROM post_actions pa
  WHERE pa.post_action_type_id = 2
    AND pa.user_id IN (SELECT id FROM staff_users)
    AND pa.created_at >= :start_date
    AND pa.created_at <= (:end_date::date + 1)
  GROUP BY action_date
) pa_staff ON dr.date = pa_staff.action_date
LEFT JOIN (
  SELECT
    date_trunc('day', p.created_at) AS post_date,
    COUNT(*) AS posts_per_day
  FROM posts p
  WHERE p.created_at >= :start_date
    AND p.created_at <= (:end_date::date + 1)
  GROUP BY post_date
) posts_count ON dr.date = posts_count.post_date
ORDER BY dr.date

التغييرات على استعلام @SaraDev الأصلي (شكرًا، سارة!):
ملخص تغييرات SQL

  1. إنشاء مجموعة الموظفين:
    تمت إضافة CTE staff_users لتحديد مستخدمي الموظفين من جدول users. يُعرَّف مستخدم الموظف بأنه أي مما يلي:
  • admin = true
  • moderator = true
  • trust_level = 4
  1. فصل إعجابات الموظفين:
    تمت إضافة استعلام فرعي لحساب عدد الإعجابات من مستخدمي الموظفين (staff_likes_count) عن طريق تصفية post_actions لـ user_id في مجموعة staff_users.
  2. إعادة تسمية عمود إعجابات غير الموظفين:
    تم تغيير تسمية الإخراج لإعجابات غير الموظفين من likes_count إلى regular_likes_count.
  3. إضافة إجمالي الإعجابات:
    تم تقديم عمود total_likes لجمع regular_likes_count و staff_likes_count.
  4. إضافة المشاركات في اليوم:
    تمت إضافة استعلام فرعي لحساب عدد المشاركات في اليوم (posts_per_day) وربطه بنطاق التاريخ.
    (نعم، ChatGPT قام بهذه القائمة من التغييرات لي أيضًا.)

نتائج مثال:

التاريخ regular_likes_count staff_likes_count posts_per_day
1/1/24 0 6 7
1/2/24 0 5 3
1/3/24 1 0 4
1/4/24 1 2 5
1/5/24 9 9 30
1/6/24 0 1 11
1/7/24 2 4 11
1/8/24 0 5 18
1/9/24 0 0 2
1/10/24 0 0 7
1/11/24 0 4 5
1/12/24 4 0 4
1/13/24 6 0 10
1/14/24 1 7 18
1/15/24 2 4 7
نفس الاستعلام المبلغ عنه حسب الأسابيع للتنعيم
-- [params]
-- integer :weeks_ago = 52

WITH date_range AS (
  SELECT date_trunc('week', series) AS week_start
  FROM generate_series(
    date_trunc('week', now()) - (:weeks_ago || ' weeks')::interval,
    date_trunc('week', now()),
    '1 week'::interval
  ) series
),
staff_users AS (
  SELECT id
  FROM users
  WHERE admin = true OR moderator = true OR trust_level = 4
)

SELECT
  dr.week_start::date AS week_start,
  COALESCE(pa_non_staff.regular_likes_count, 0) AS regular_likes_count,
  COALESCE(pa_staff.staff_likes_count, 0) AS staff_likes_count,
  COALESCE(pa_non_staff.regular_likes_count, 0) + COALESCE(pa_staff.staff_likes_count, 0) AS total_likes,
  COALESCE(posts_count.posts_per_week, 0) AS posts_per_week
FROM
  date_range dr
LEFT JOIN (
  SELECT
    date_trunc('week', pa.created_at) AS action_week,
    COUNT(*) AS regular_likes_count
  FROM post_actions pa
  WHERE pa.post_action_type_id = 2
    AND pa.user_id NOT IN (SELECT id FROM staff_users)
    AND pa.created_at >= date_trunc('week', now()) - (:weeks_ago || ' weeks')::interval
    AND pa.created_at <= date_trunc('week', now())
  GROUP BY action_week
) pa_non_staff ON dr.week_start = pa_non_staff.action_week
LEFT JOIN (
  SELECT
    date_trunc('week', pa.created_at) AS action_week,
    COUNT(*) AS staff_likes_count
  FROM post_actions pa
  WHERE pa.post_action_type_id = 2
    AND pa.user_id IN (SELECT id FROM staff_users)
    AND pa.created_at >= date_trunc('week', now()) - (:weeks_ago || ' weeks')::interval
    AND pa.created_at <= date_trunc('week', now())
  GROUP BY action_week
) pa_staff ON dr.week_start = pa_staff.action_week
LEFT JOIN (
  SELECT
    date_trunc('week', p.created_at) AS post_week,
    COUNT(*) AS posts_per_week
  FROM posts p
  WHERE p.created_at >= date_trunc('week', now()) - (:weeks_ago || ' weeks')::interval
    AND p.created_at <= date_trunc('week', now())
  GROUP BY post_week
) posts_count ON dr.week_start = posts_count.post_week
ORDER BY dr.week_start

في حال كان الأمر مثيرًا للاهتمام، إليك الاستعلامات النهائية التي عدلت استعلام سارة:

لدي استعلام SQL يقدم عدد الإعجابات اليومية (likes_count) بين تاريخين، ولكن أحتاج إلى إجراء التحسينات التالية لإنتاج مخرجات نهائية تجمع البيانات حسب الأسابيع وتتضمن تفاصيل إضافية:

  1. تحديد مجموعة الموظفين:
  • إنشاء مجموعة staff_users من جدول users. يجب اعتبار المستخدم موظفًا إذا استوفى أيًا من المعايير التالية:
    • admin = true
    • moderator = true
    • trust_level = 4
  1. فصل الإعجابات حسب الموظفين وغير الموظفين:
  • إضافة عمودين منفصلين:
    • regular_likes_count: عدد الإعجابات من المستخدمين غير الموظفين.
    • staff_likes_count: عدد الإعجابات من مستخدمي الموظفين.
  • التأكد من أن عمود regular_likes_count يستبعد الإعجابات التي أنشأها مستخدمو الموظفين.
  1. إضافة إجمالي الإعجابات:
  • تضمين عمود total_likes الذي يجمع regular_likes_count و staff_likes_count.
  1. إضافة المشاركات لكل فترة:
  • إضافة عمود posts_per_week الذي يحسب عدد المشاركات التي تم إنشاؤها خلال كل أسبوع.
  1. التجميع حسب الأسابيع:
  • تعديل الاستعلام لتجميع جميع البيانات حسب فترات أسبوعية بدلاً من يومية.
  • تضمين عمود week_start الذي يمثل تاريخ بداية كل أسبوع.
  1. الحد حسب الأسابيع الماضية:
  • تقديم معلمة :weeks_ago لتحديد النتائج إلى آخر N أسبوع. يجب أن تكون القيمة الافتراضية 52 أسبوعًا (سنة واحدة).
  1. الترتيب والأعمدة النهائية:
  • التأكد من أن المخرجات مرتبة حسب week_start وتتضمن الأعمدة التالية بهذا الترتيب:
    1. week_start: تاريخ بداية الأسبوع.
    2. regular_likes_count: عدد الإعجابات من المستخدمين غير الموظفين.
    3. staff_likes_count: عدد الإعجابات من مستخدمي الموظفين.
    4. total_likes: مجموع regular_likes_count و staff_likes_count.
    5. posts_per_week: عدد المشاركات التي تم إنشاؤها خلال الأسبوع.
إعجابَين (2)