我正在努力解决一个有趣的问题。我有一个表,除了其他数据之外,还有这些列(此示例中的日期以欧洲格式显示 - 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
基本上,每个地方可能会多次访问 - 日期可能是过去(完成访问)或未来(计划访问)。为简单起见,今天的访问是未来计划访问的一部分。
现在,我需要在此表上运行一个select,它会从此表中提取唯一地点ID(没有日期),按以下顺序排序:
例如,对于上面显示的示例数据,我需要的结果是:
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。如果我尝试将distinct
添加到select语句中,postgres会抱怨我必须在select子句中使用order by
- 但是那时唯一的不再合理,因为我在那里有日期
不知怎的,我觉得应该有一种方法可以在一个select语句中得到我需要的结果,但是我无法理解如何做到这一点。
如果无法做到这一点,那么,当然,我将不得不在代码中完成所有工作,但我更愿意在一个SQL语句中使用它。
P.S。我并不担心性能,因为我要排序的数据集并不大。在应用where
子句后,它很少包含超过10条记录。
答案 0 :(得分: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
@
有助于排序“最接近的第一个”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
答案 1 :(得分: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))