1

私は興味深い問題を解決しようとしています。他のデータの中でも、これらの列を含むテーブルがあります (このサンプルの日付はヨーロッパ形式で表示されています - dd/mm/yyyy):

n_place_id   dt_visit_date
(integer)    (date)
==========   =============
   1           10/02/2012
   3           11/03/2012
   4           11/05/2012
  13           14/06/2012
   3           04/10/2012
   3           03/11/2012
   5           05/09/2012
  13           18/08/2012

基本的に、各場所は複数回訪問することができ、日付は過去 (完了した訪問) または将来 (計画された訪問) の場合があります。簡単にするために、今日の訪問は計画された将来の訪問の一部です。

ここで、このテーブルで選択を実行する必要があります。これにより、このテーブルから一意の場所 ID (日付なし) が取得され、次の順序で並べ替えられます。

  1. 今後の訪問は過去の訪問の前に行われます
  2. 今後の訪問は、同じ場所への過去の訪問よりも優先されます
  3. 今後の訪問については、同じ場所のソートで最も古い日付を優先する必要があります
  4. 過去の訪問の場合、同じ場所のソートでは最新の日付が優先される必要があります。

たとえば、上記のサンプル データの場合、必要な結果は次のとおりです。

 5     (earliest future visit)
 3     (next future visit into the future)
13     (latest past visit)
 4     (previous past visit)
 1     (earlier visit in the past)

これで、次のように句を使用case whenして目的の並べ替えを実現できます。order by

select
    n_place_id
from
    place_visit
order by
    (case when dt_visit_date >= now()::date then 1 else 2 end),
    (case when dt_visit_date >= now():: date then 1 else -1 end) * extract(epoch from dt_visit_date)

これはが必要とすることを行いますが、重複する ID が含まれていますが、一意の場所 ID が必要です。select ステートメントに追加しようとするdistinctと、postgres はorder by、select 句に が必要であると不平を言いますが、そこに日付があるため、unique はもはや意味がありません。

どういうわけか、1 つの select ステートメントで必要な結果を取得する方法があるはずだと感じていますが、その方法について頭を悩ませることはできません。

これができない場合は、もちろん、コード内ですべてを実行する必要がありますが、これを 1 つの SQL ステートメントで行うことをお勧めします。

PS ソートするデータセットは大きくないため、パフォーマンスについては心配していません。句が適用されると、where約 10 を超えるレコードが含まれることはほとんどありません。

4

2 に答える 2

2

DISTINCT ON結果として、行の追加の列を簡単に表示できn_place_idます。

SELECT n_place_id, dt_visit_date
FROM  (
   SELECT DISTINCT ON (n_place_id) *
         ,dt_visit_date < now()::date    AS prio  -- future first
         ,@(now()::date - dt_visit_date) AS diff  -- closest first
   FROM   place_visit
   ORDER  BY n_place_id, prio, diff
   ) x
ORDER  BY prio, diff;

n_place_id事実上、過去の日付または過去の日付ごとに、最も早い将来の日付 (「今日」を含む) の行を選択しますが、それは失敗します。
次に、結果の一意の行が同じ基準で並べ替えられます。

  • FALSE前に並べ替えるTRUE
  • 絶対値」@は「最も近いものから」ソートするのに役立ちます
  • Postgres 固有の詳細についてはDISTINCT ON、この関連する回答を参照してください。

結果:

 n_place_id | dt_visit_date
------------+--------------
 5          | 2012-09-05
 3          | 2012-10-04
 13         | 2012-08-18
 4          | 2012-05-11
 1          | 2012-02-10
于 2012-09-04T13:16:27.947 に答える
1

これを試して

 select n_place_id
 from 
 (
    select *, 
    extract(epoch from (dt_visit_date - now())) as seconds,  
    1 - SIGN(extract(epoch from (dt_visit_date - now())) ) as futurepast
    from #t
 ) v
 group by n_place_id
 order by max(futurepast) desc, min(abs(seconds))
于 2012-09-03T09:45:40.690 に答える