3

一種のイベント カレンダー アプリを作成しています。ユーザーのホームページには、次の 2 種類のイベントが表示されます。

  1. 近くのイベント - 予定日が今後 3 日以内または過去 1 時間以内のもの。
  2. 通常のイベント - 予定日がないか、予定日が 3 日以上先のイベント。

これはイベントテーブルです。id, user_id, content, occurs_at, created_at

現在、これらのイベントを作成日順に表示して、新しく追加されたものを最初に表示しています。

私が望むのは、最初にすべての近くのイベントを表示し、スケジュールの日付で並べ替えてから、通常のイベントを表示して、作成された日付で並べ替えることです。ユーザーエクスペリエンスが向上すると思いますが、どうすればよいかわかりません。

アップデート

このクエリは、いくつかの回答の組み合わせです。

ORDER BY COALESCE(occurs_at > :min_time AND occurs_at < :max_time, 0) DESC, occurs_at ASC, created_at DESC

4

4 に答える 4

2

詳細形式

説明/理解が容易。

WITH x AS (
   SELECT *
        , COALESCE(occurs_at <= (now() + interval '3 days'), FALSE) AS nearby
   FROM   events
   WHERE  occurs_at >= now() - interval '1 hour' -- exclude older events
      OR  occurs_at IS NULL
   )      -- CTE is not strictly necessary, just to make ORDER BY clearer
SELECT *
FROM   x
ORDER  BY
       nearby DESC
     , CASE WHEN nearby THEN occurs_at ELSE created_at END

occurs_at質問では明示的に定義されていませんが、言及された「予定日なし」は、NULL. したがって、、COALESCEまたはFALSEおよびNULLを使用すると、異なる方法でソートされます。

  • まず、nearbyCTE で計算された順序で並べ替えxます。
  • 次に、それぞれの日付 (occurs_atまたはcreated_at) で並べ替えます。
    • occurs_NULLatはnearbyイベントには使用できません。
    • そして、そもそもcreated_at定義されていると思いNOT NULLます。それ以外の場合は、値をどこに置くかを決定する必要がありNULLます。

ここでの他の回答は、定数と比較する前に列に基づいて値を計算することを提案しています。これにより、パフォーマンスが非常に低下する可能性があります。例:

date_diff(d,occurs_at, now) <= 3  -- date_diff is also tSQL, not Postgres

回避できる場合は、これを行わないでください。これにより、Postgres はすべての行の値を計算するようになり、単純なインデックスを使用できなくなります。この最近の密接に関連した回答の詳細情報。

シンプルバージョン

短く、少し速く。

SELECT *
FROM   events
WHERE  occurs_at >= now() - interval '1h'
   OR  occurs_at IS NULL
ORDER  BY
       COALESCE( occurs_at <= (now()::date + 3), FALSE) DESC
     , CASE WHEN occurs_at <= (now()::date + 3)
            THEN occurs_at ELSE created_at END;

@Joachim の sqlfiddle を使用し、セットアップを簡素化し、欠落しているケース (スケジュールされていない、過去に発生したもの) を追加し、それに対してクエリを実行しました:
-> sqlfiddle

于 2012-10-04T21:55:38.650 に答える
2

@MarcBが言及しているように、式で注文できますが、PostgreSQLの場合、式は多少異なります。

SELECT * FROM Events
ORDER BY CASE WHEN (occurs_at - '3 days'::interval) < CURRENT_TIMESTAMP 
         THEN occurs_at
         ELSE '9999-01-01'::timestamp
         END, created_at;

SQLfiddle デモ.

「9999-01-01」は、「maxdate」の PostgreSQL 定数を知っている人がいる場合は、少し不器用に任意に選択された日付であることに注意してください:)

于 2012-10-04T20:23:18.720 に答える
2

order by句には、フィールド名だけでなく、任意のロジックを含めることができるため、疑似コードでは、

SELECT ...
...
ORDER BY (date_diff(occurs_at, now) <= '3 days'), occurs_at DESC, created_at DESC

最初の句は、次の 3 日以内に発生するすべてのイベントをリストの一番上に強制します。2 番目の句はそれらを降順で並べ替え、それ以外はすべて created_at の日付で並べ替えます。

于 2012-10-04T19:36:14.477 に答える
1

「近くに」あるかどうかを判断するフィールドでSELECT句を拡張します(場所ではなく時間的に)

SELECT
id, user_id, content, occurs_at, created_at,
case when date_diff(d,occurs_at, now) <= 3 then 1 else 0 end as isNearby
...

しかし、あなたの構文はよくわかりません。これはMS SQL Server用です

于 2012-10-04T19:40:43.900 に答える