تجميع بيانات تقرير لوحة التحكم حسب الفترة الزمنية

لقد قمت مؤخرًا بكتابة استعلامات لـ Data Explorer تعيد بيانات مشابهة لتلك الموجودة في تقارير لوحة معلومات Discourse، ولكنها تسمح بتجميع البيانات حسب فترة زمنية. على سبيل المثال، إظهار عدد المواضيع المنشورة بين تواريخ بداية ونهاية محددة، مع تجميع الإجماليات على أساس أسبوعي بدلاً من يومي.

يتم تحديد معلمات الاستعلام وفقًا للقواعد التالية:

معلمات الاستعلام: query_interval (فاصل زمني Postgres، مثل ‘1 day’، ‘7 days’، ‘1 week’، ‘1 month’)، start_date (‘yyyy-mm-dd’)، end_date (‘yyyy-mm-dd’)، category_ids (قائمة مفصولة بفواصل من معرّفات الفئات، الافتراضي هو -1)، include_subcategories (قيمة منطقية، الافتراضي هو true). يعيد عدد المنشورات المنشورة بين تواريخ البداية والنهاية المحددة. يتم تجميع النتائج حسب فاصل الاستعلام. إذا كانت قائمة category_ids تحتوي على القيمة -1، فستُعاد النتائج لجميع الفئات.

متوسط الوقت حتى أول رد للفترة

--[params]
-- string :query_interval = 7 days
-- date :start_date
-- date :end_date
-- int_list :category_ids = -1
-- boolean :include_subcategories = true

WITH query_periods AS (
  SELECT generate_series(:start_date, :end_date, :query_interval::interval)::date as period_start
),
subcategory_ids AS (
    SELECT id FROM categories
    WHERE parent_category_id IN (:category_ids)
),
sub_subcategory_ids AS (
    SELECT id FROM categories
    WHERE parent_category_id IN (SELECT id FROM subcategory_ids)
),

topics_and_replies AS (
    SELECT
    t.created_at AS topic_created_at,
    p.topic_id AS reply_topic_id,
    p.created_at AS reply_created_at,
    period_start
    FROM topics t
    JOIN query_periods
    ON t.created_at::date >= period_start AND t.created_at::date < period_start + interval :query_interval
    JOIN posts p
    ON p.topic_id = t.id
    WHERE t.posts_count > 1
    AND t.archetype = 'regular'
    AND t.deleted_at IS NULL
    AND CASE
        WHEN -1 IN (:category_ids)
            THEN true
        WHEN :include_subcategories = false
            THEN t.category_id IN (:category_ids)
        ELSE t.category_id IN (:category_ids) OR t.category_id IN (SELECT id FROM subcategory_ids) OR t.category_id IN (SELECT id FROM sub_subcategory_ids)
    END
    AND p.post_number > 1
    AND p.post_type = 1
    AND p.deleted_at IS NULL
)

SELECT period_start, ROUND(AVG(reply_time_hours)::numeric, 2) AS response_time_hours FROM(
    SELECT
    qp.period_start,
    EXTRACT(EPOCH FROM MIN(reply_created_at) - topic_created_at):: float / 3600 AS reply_time_hours
    FROM query_periods qp
    JOIN topics_and_replies tar
    ON tar.period_start = qp.period_start
    GROUP BY reply_topic_id, topic_created_at, qp.period_start
) replies_for_period
GROUP BY period_start
ORDER BY period_start

إجمالي الحلول للفترة

--[params]
-- string :query_interval = 7 days
-- date :start_date
-- date :end_date
-- int_list :category_ids = -1
-- boolean :include_subcategories = true

WITH query_periods AS (
  SELECT generate_series(:start_date, :end_date, :query_interval::interval)::date as period_start
),
subcategory_ids AS (
    SELECT id FROM categories
    WHERE parent_category_id IN (:category_ids)
),
sub_subcategory_ids AS (
    SELECT id FROM categories
    WHERE parent_category_id IN (SELECT id FROM subcategory_ids)
)

SELECT
period_start,
COUNT(1) AS solved_count
FROM user_actions ua
JOIN query_periods
ON ua.created_at::date >= period_start AND ua.created_at::date < period_start + interval :query_interval
JOIN topics t
ON t.id = ua.target_topic_id
JOIN posts p 
ON p.id = ua.target_post_id
WHERE ua.action_type = 15
AND t.deleted_at IS NULL
AND p.deleted_at IS NULL
AND CASE
    WHEN -1 IN (:category_ids)
        THEN true
    WHEN :include_subcategories = false
        THEN t.category_id IN (:category_ids)
    ELSE t.category_id IN (:category_ids) OR t.category_id IN (SELECT id FROM subcategory_ids) OR t.category_id IN (SELECT id FROM sub_subcategory_ids)
END
GROUP BY period_start
ORDER BY period_start

عدد المواضيع للفترة

--[params]
-- string :query_interval = 7 days
-- date :start_date
-- date :end_date
-- int_list :category_ids = -1
-- boolean :include_subcategories = true

WITH query_periods AS (
  SELECT generate_series(:start_date, :end_date, :query_interval::interval)::date as period_start
),
subcategory_ids AS (
    SELECT id FROM categories
    WHERE parent_category_id IN (:category_ids)
),
sub_subcategory_ids AS (
    SELECT id FROM categories
    WHERE parent_category_id IN (SELECT id FROM subcategory_ids)
)

SELECT qp.period_start,
COUNT(t.id)
FROM query_periods qp
JOIN topics t
ON t.created_at::date >= qp.period_start AND t.created_at::date < qp.period_start + interval :query_interval
WHERE t.deleted_at IS NULL
AND t.archetype = 'regular'
AND CASE
    WHEN -1 IN (:category_ids)
        THEN true
    WHEN :include_subcategories = false
        THEN t.category_id IN (:category_ids)
    ELSE t.category_id IN (:category_ids) OR t.category_id IN (SELECT id FROM subcategory_ids) OR t.category_id IN (SELECT id FROM sub_subcategory_ids)
END
GROUP BY qp.period_start
ORDER BY qp.period_start

عدد المنشورات للفترة

--[params]
-- string :query_interval = 7 days
-- date :start_date
-- date :end_date
-- int_list :category_ids = -1
-- boolean :include_subcategories = true

WITH query_periods AS (
  SELECT generate_series(:start_date, :end_date, :query_interval::interval)::date as period_start
),
subcategory_ids AS (
    SELECT id FROM categories
    WHERE parent_category_id IN (:category_ids)
),
sub_subcategory_ids AS (
    SELECT id FROM categories
    WHERE parent_category_id IN (SELECT id FROM subcategory_ids)
)

SELECT
period_start,
COUNT(p.id)
FROM query_periods qp
JOIN posts p
ON p.created_at::date >= qp.period_start AND p.created_at::date < qp.period_start + interval :query_interval
JOIN topics t
ON t.id = p.topic_id
WHERE t.archetype = 'regular'
AND t.deleted_at IS NULL
AND CASE
    WHEN -1 IN (:category_ids)
        THEN true
    WHEN :include_subcategories = false
        THEN t.category_id IN (:category_ids)
    ELSE t.category_id IN (:category_ids) OR t.category_id IN (SELECT id FROM subcategory_ids) OR t.category_id IN (SELECT id FROM sub_subcategory_ids)
END
AND p.deleted_at IS NULL
AND p.post_type = 1
GROUP BY period_start
ORDER BY period_start

شكرًا لك @simon - هذه ممتازة!

لقد كنت في البداية مرتبكًا بسبب استمرار اشتراط وجود معاملات start_date و end_date عند تحديد فترة زمنية، والعكس صحيح. الآن أدركت أن النتيجة تُرجع حسب كل فترة زمنية X، ضمن النطاق الزمني المحدد. هذا مفيد جدًا للنظر السريع في التغيرات الشهرية على مدار عام، أو سيناريوهات مماثلة.

إدراج الفئات والفئات الفرعية رائع - فأنا أراقب النشاط في أجزاء مختلفة من مجتمعي، لذا فإن القدرة على النظر بسرعة في أداء فئة كاملة مع فئاتها الفرعية أمر مفيد للغاية.

هل توجد طريقة بسيطة لتعديل هذه الاستعلامات لعرض نتائج الفئات الفرعية في قائمة مفصولة بفواصل؟

على سبيل المثال: المنشورات التي نُشرت خلال الفترة الزمنية في الفئة 1 (10 منشورات)، 2 (20 منشورًا) و3 (30 منشورًا).

إضافة category_ids 1,2,3 إلى الاستعلام يُرجع إجماليًا (60 منشورًا). أود جدًا الحصول على طريقة تُرجع 10,20,30. سيسمح ذلك بإجراء مقارنات جنبًا إلى جنب بين الفئات.

هذا ممكن. ومن الأسهل تعديل الاستعلامات لإرجاع صف واحد لكل فئة. ويمكن تحقيق ذلك بتغيير جملة GROUP BY النهائية لتشمل معرف الفئة. لم أجرب هذا مع جميع الأمثلة التي نشرتها، لكن إليك تعديلًا لاستعلام “عدد المنشورات للفترة الزمنية” يقوم بذلك:

--[params]
-- string :query_interval = 7 days
-- date :start_date
-- date :end_date
-- int_list :category_ids = -1
-- boolean :include_subcategories = true

WITH query_periods AS (
  SELECT generate_series(:start_date, :end_date, :query_interval::interval)::date as period_start
),
subcategory_ids AS (
    SELECT id FROM categories
    WHERE parent_category_id IN (:category_ids)
),
sub_subcategory_ids AS (
    SELECT id FROM categories
    WHERE parent_category_id IN (SELECT id FROM subcategory_ids)
)

SELECT
period_start,
t.category_id,
COUNT(p.id)
FROM query_periods qp
JOIN posts p
ON p.created_at::date >= qp.period_start AND p.created_at::date < qp.period_start + interval :query_interval
JOIN topics t
ON t.id = p.topic_id
WHERE t.archetype = 'regular'
AND t.deleted_at IS NULL
AND CASE
    WHEN -1 IN (:category_ids)
        THEN true
    WHEN :include_subcategories = false
        THEN t.category_id IN (:category_ids)
    ELSE t.category_id IN (:category_ids) OR t.category_id IN (SELECT id FROM subcategory_ids) OR t.category_id IN (SELECT id FROM sub_subcategory_ids)
END
AND p.deleted_at IS NULL
AND p.post_type = 1
GROUP BY period_start, t.category_id
ORDER BY period_start

إليك كيف تبدو النتائج على موقع التطوير الخاص بي:

رائع - شكراً مرة أخرى! أعتقد أن هذا سيفعل ما أحتاجه :slight_smile:

هذا رائع يا @simon شكراً لك.
سامحني على سؤالي البسيط، ولكن هل من الممكن:

  1. تضمين تقارير مكتوبة مخصصة في قسم لوحة المعلومات والتقارير، وكيف؟
  2. تشغيل إجراء ما بناءً على نتيجة استعلام تم تشغيله في مستكشف البيانات - على سبيل المثال، إرسال رسالة إلى المسؤولين؟

شكراً