ダッシュボードレポート - 応答なしのトピック

これは、応答のないトピックのダッシュボードレポートのSQLバージョンです。
ダッシュボードレポートは、指定された期間内に作成され、他のユーザーからの応答がなかったトピックの数をカウントするように設計されています。このレポートは特定のカテゴリでフィルタリングでき、オプションでサブカテゴリを含めることができます。

-- [params]
-- date :start_date = 2024-01-01
-- date :end_date = 2024-02-01
-- null int :category_id
-- boolean :include_subcategories = false

WITH no_response_total AS (
SELECT *
    FROM (
      SELECT t.id, t.created_at, MIN(p.post_number) first_reply
      FROM topics t
      LEFT JOIN posts p ON p.topic_id = t.id AND p.user_id != t.user_id AND p.deleted_at IS NULL AND p.post_type = 1
      WHERE t.archetype <> 'private_message'
      AND t.deleted_at ISNULL
      AND (
        :category_id IS NULL
        OR t.category_id = :category_id
        OR (
          :include_subcategories
          AND t.category_id IN (
            SELECT id FROM categories WHERE parent_category_id = :category_id
          )
        )
      )
      GROUP BY t.id
    ) tt
    WHERE tt.first_reply IS NULL OR tt.first_reply < 2
)

SELECT
  DATE(nrt.created_at) AS date,
  COUNT(nrt.id) AS topics_without_response
FROM no_response_total nrt
WHERE nrt.created_at::date BETWEEN :start_date AND :end_date
GROUP BY date
ORDER BY date ASC

パラメータ

  • 日付パラメータ:
    • クエリは、レポートの日付範囲を定義する2つのパラメータ、:start_date:end_dateを受け入れます。両方のdateパラメータは YYYY-MM-DDの日付形式を受け入れます。
  • カテゴリパラメータ:
    • :category_id: 特定のカテゴリのIDに設定して、そのカテゴリ内の投稿に分析を絞り込むことができる整数パラメータ。nullに設定されているか、提供されていない場合、すべてのカテゴリのトピックが考慮されます。
    • :include_subcategories: 指定された:category_idのサブカテゴリからの投稿を含めるかどうかを制御するブールパラメータ。trueに設定されている場合、レポートには指定されたカテゴリとそのサブカテゴリの両方の投稿へのリンクが含まれます。falseの場合、指定されたカテゴリのみが考慮されます。

SQLクエリの説明

クエリは、no_response_totalという名前の共通テーブル式(CTE)から始まります。このCTEは次の手順を実行します。

  • トピックの選択: topicsテーブルからすべてのトピック(t.id)とその作成日(t.created_at)を選択します。
  • 投稿との左結合: postsテーブルとの左結合を実行して、各トピックへの最初の返信を見つけます。結合条件は、投稿がトピック作成者によるものではないこと(p.user_id != t.user_id)、投稿が削除されていないこと(p.deleted_at IS NULL)、および投稿がタイプ1(通常は標準の返信を表す)であることを保証します。
  • トピックのフィルタリング: クエリは、プライベートメッセージ(t.archetype <> 'private_message')であるトピックと、削除されたトピック(t.deleted_at ISNULL)を除外します。
  • カテゴリフィルタリング: :category_idが提供されている場合、クエリは指定されたカテゴリのトピックのみを含めるようにトピックをフィルタリングします。:include_subcategoriesがtrueの場合、指定されたカテゴリのサブカテゴリからのトピックも含まれます。
  • グループ化と最小投稿番号: トピックはIDごとにグループ化され、最初の返信を見つけるために最小投稿番号(MIN(p.post_number))が計算されます。
  • 応答なしのフィルタリング: サブクエリttは、投稿番号が2以上である最初の返信を持つトピックを除外し、返信のないトピック(tt.first_reply IS NULL)または元の投稿のみ(tt.first_reply < 2)を残します。

no_response_total CTEが定義された後、メインクエリは次のことを行います。

  • 日付範囲によるフィルタリング: CTEからのトピックを指定された開始日と終了日(:start_date:end_date)でフィルタリングします。
  • 応答のないトピックのカウント: 指定された範囲内の各日付について、応答のないトピックの数をカウントします。
  • 日付によるグループ化: 結果は、トピック作成日(DATE(nrt.created_at))でグループ化されます。
  • 順序付け: 結果は日付の昇順で並べ替えられます。

結果例

date topics_without_response
2024-01-02 4
2024-01-03 8
2024-01-04 4
2024-01-05 3
2024-01-06 3
「いいね!」 1

パラメータを含まないバージョンを作成していただけますか?パラメータが設定されているため、このコードの使用に苦労しています。7日間を遡るバージョンを作成して、メールで送信したいのです。

ありがとうございます。

「いいね!」 1

はい、パラメータを使用せずに現在の日付から7日間を遡る更新版クエリを以下に示します。:slightly_smiling_face:

このバージョンには、カテゴリまたはサブカテゴリによるフィルタリングは含まれていません。

WITH no_response_total AS (
  SELECT *
  FROM (
    SELECT 
      t.id, 
      t.created_at, 
      MIN(p.post_number) AS first_reply
    FROM 
      topics t
    LEFT JOIN 
      posts p 
    ON 
      p.topic_id = t.id 
      AND p.user_id != t.user_id 
      AND p.deleted_at IS NULL 
      AND p.post_type = 1
    WHERE 
      t.archetype <> 'private_message'
      AND t.deleted_at IS NULL
      AND (
        t.category_id = :category_id
        OR t.category_id IN (
          SELECT id FROM categories WHERE parent_category_id = :category_id
        )
      )
    GROUP BY 
      t.id
  ) tt
  WHERE 
    tt.first_reply IS NULL 
    OR tt.first_reply < 2
)

SELECT 
  DATE(nrt.created_at) AS date, 
  COUNT(nrt.id) AS topics_without_response
FROM 
  no_response_total nrt
WHERE 
  nrt.created_at::date BETWEEN CURRENT_DATE - INTERVAL '7 days' AND CURRENT_DATE
GROUP BY 
  date
ORDER BY 
  date ASC

クエリが遡る期間を調整したい場合は、クエリのこの行を変更するだけです。

nrt.created_at::date BETWEEN CURRENT_DATE - INTERVAL '7 days' AND 
「いいね!」 1

ご返信ありがとうございます。今は別のことに集中しており、戻ってくる時間がなかったので、次回必要になったらまたこちらに戻ってきます。

「いいね!」 1

こんにちは。

これを日付駆動ではなく、月と年で表示できるようにするのに苦労しています。

これを機能させるためにいくつかのことを試しましたが、列が存在するにもかかわらず(WITHステートメント内で作成し、その後参照しているのに)、列が存在しないと常に表示されます。

日ごとに返信のないトピックを確認するのではなく、年ごと、月ごとなどに確認できるように、このコードをどのように修正すればよいでしょうか。

よろしくお願いします。

こんにちは、ソフィー様

返信のないトピックを年、月、その他の時間間隔で集計できるようにクエリを変更するには、date_trunc 関数の interval パラメータに目的の間隔を指定するパラメータを追加することで実現できます。

例えば、次のようになります。

-- [params]
-- date :start_date = 2024-01-01
-- date :end_date = 2025-01-01
-- null int :category_id
-- boolean :include_subcategories = false
-- text :interval = day -- Options: day, week, month, year

WITH no_response_total AS (
  SELECT *
  FROM (
    SELECT t.id, t.created_at, MIN(p.post_number) first_reply
    FROM topics t
    LEFT JOIN posts p ON p.topic_id = t.id AND p.user_id != t.user_id AND p.deleted_at IS NULL AND p.post_type = 1
    WHERE t.archetype <> 'private_message'
      AND t.deleted_at ISNULL
      AND (
        :category_id IS NULL
        OR t.category_id = :category_id
        OR (
          :include_subcategories
          AND t.category_id IN (
            SELECT id FROM categories WHERE parent_category_id = :category_id
          )
        )
      )
    GROUP BY t.id
  ) tt
  WHERE tt.first_reply IS NULL OR tt.first_reply < 2
)

SELECT
  date_trunc(:interval, nrt.created_at)::date AS period,
  COUNT(nrt.id) AS topics_without_response
FROM no_response_total nrt
WHERE nrt.created_at::date BETWEEN :start_date AND :end_date
GROUP BY period
ORDER BY period ASC

パラメータを削除したい場合は、代わりに次のようなクエリを使用することもできます。

WITH no_response_total AS (
  SELECT *
  FROM (
    SELECT t.id, t.created_at, MIN(p.post_number) first_reply
    FROM topics t
    LEFT JOIN posts p ON p.topic_id = t.id AND p.user_id != t.user_id AND p.deleted_at IS NULL AND p.post_type = 1
    WHERE t.archetype <> 'private_message'
      AND t.deleted_at ISNULL
    GROUP BY t.id
  ) tt
  WHERE tt.first_reply IS NULL OR tt.first_reply < 2
)

SELECT
  date_trunc('year', nrt.created_at)::date AS period,
  COUNT(nrt.id) AS topics_without_response
FROM no_response_total nrt
WHERE nrt.created_at::date BETWEEN '2024-01-01' AND '2025-01-01'
GROUP BY period
ORDER BY period ASC

ありがとうございます。これで年を取得する方法が解決しました。

しかし、また行き詰まってしまいました。PostgreSQL の日付の動作が異なるようです。

to_char(t.created_at, 'MM-YY') as Yearmonth,

これは「10-22」(10月-22日)を表す 10-22 を返します。

10-22 を Oct-22 に変更するにはどうすればよいですか?ディスコース内でガイダンスを探しましたが、見つけられませんでした。どこを見ればよいのかわからないのかもしれません。

よろしくお願いします。

PostgreSQL で日付の形式を 10-22 から Oct-22 に変更するには、TO_CHAR 関数を使用できます。この関数を使用すると、さまざまな方法で日付をフォーマットできます。たとえば、次のようになります。

SELECT
TO_CHAR(TO_DATE('10-22', 'MM-YY'), 'Mon-YY') AS formatted_date

この SQL ステートメントでは:

  • TO_DATE('10-22', 'MM-YY') は、MM-YY の形式を使用して文字列 10-22 を日付型に変換します。
  • TO_CHAR(..., 'Mon-YY') は、この日付をフォーマットして、省略された月名とそれに続く年を表示し、Oct-22 を生成します。

上記で共有された Topics with No Response クエリの interval パラメータに基づいた別の例を次に示します。

-- [params]
-- date :start_date = 2024-01-01
-- date :end_date = 2025-01-01
-- null int :category_id
-- boolean :include_subcategories = false
-- text :interval = month

WITH no_response_total AS (
  SELECT *
  FROM (
    SELECT t.id, t.created_at, MIN(p.post_number) first_reply
    FROM topics t
    LEFT JOIN posts p ON p.topic_id = t.id AND p.user_id != t.user_id AND p.deleted_at IS NULL AND p.post_type = 1
    WHERE t.archetype <> 'private_message'
      AND t.deleted_at ISNULL
      AND (
        :category_id IS NULL
        OR t.category_id = :category_id
        OR (
          :include_subcategories
          AND t.category_id IN (
            SELECT id FROM categories WHERE parent_category_id = :category_id
          )
        )
      )
    GROUP BY t.id
  ) tt
  WHERE tt.first_reply IS NULL OR tt.first_reply < 2
)

SELECT
  TO_CHAR(date_trunc(:interval, nrt.created_at)::date, 'Mon-YY') AS period,
  COUNT(nrt.id) AS topics_without_response
FROM no_response_total nrt
WHERE nrt.created_at::date BETWEEN :start_date AND :end_date
GROUP BY period, date_trunc(:interval, nrt.created_at)::date
ORDER BY date_trunc(:interval, nrt.created_at)::date ASC

参考までに、このクエリの結果は次のようになります。

期間 応答のないトピック
23年12月 123
24年1月 455
24年2月 789
「いいね!」 1

ありがとうございます!