获取一组记录的最近日期到给定日期

时间:2015-09-26 15:44:15

标签: sql postgresql date

大家好我的SQL查询有问题,看,这是我的方案:

我有一张学生桌和一张桌子,我在那里存储学生进入或离开学校的日期,所以我想得到每个学生最近的约会日期,我找不到这样做的方法。

Students Data:

|idstudent|name  |
------------------
|    1    | John |
|    2    | Bob  |
------------------

Dates Data: 

|id|idstudent|   date   |type|
------------------------------
|1 |   1     |20-01-2015| 1  |
|2 |   2     |20-01-2015| 1  |
|3 |   2     |15-08-2015| 2  |
|4 |   1     |31-08-2015| 2  |
------------------------------

Desired Date = 01-08-2015 

|idstudent| name  | date       |type|
-------------------------------------
|    1    | John  | 31-08-2015 | 2  |
|    2    | Bob   | 15-08-2015 | 2  |

学生表:

CREATE TABLE students
(
  idstudent serial NOT NULL,
  name character varying(200),
  CONSTRAINT idstudent PRIMARY KEY (idstudent)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE students
  OWNER TO postgres;

日期表:

CREATE TABLE students_dates
(
  idstudent_date serial NOT NULL,
  idstudent bigint,
  date_ date,
  type smallint,
  CONSTRAINT idstudent_date PRIMARY KEY (idstudent_date)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE students_dates
  OWNER TO postgres;

任何人都可以帮助我吗?

非常感谢你。

4 个答案:

答案 0 :(得分:3)

使用专有distinct on ()在Postgres中通常比使用窗口函数更快。

使用abs()建立Gordon的想法:

select distinct on (s.idstudent) s.*, sd.date_, sd.type
from students s
  join students_dates sd on s.idstudent = sd.idstudent
order by s.idstudent, abs(sd.date_ - date '2015-09-26');

这也可以使用Window函数解决:

select idstudent, name, date_, type
from (
  select s.idstudent, s.name, sd.date_, sd.type, 
         row_number() over (partition by s.idstudent order by sd.date_ - date '2015-09-26' desc) as rn
  from students s
    join students_dates sd on s.idstudent = sd.idstudent
) t
where rn = 1;

SQLFiddle:http://sqlfiddle.com/#!15/25fef/4

答案 1 :(得分:1)

使用DATEDIFF获取日期之间的差异,获取ABS值。然后按ABS(DATEDIFF())排序并获得最高记录。

答案 2 :(得分:1)

这有点棘手。我认为最好的方法是distinct on。您没有在问题中描述数据,但这是一个想法:

select distinct on (studentid) s.*
from students s
order by studentid, abs(studentdate - '2015-09-26');

答案 3 :(得分:1)

如果我理解你的要求,这就是答案。 在排名后,它将学生表与学生日期表连接起来,并且只占用最接近您GIVEN_DATE的日期。

SELECT s.* FROM students s
INNER JOIN
(SELECT date,type FROM (
 SELECT sd2.*,RANK() OVER(PARTITION BY sd2.idstudent ORDER BY abs(sd2.date - GIVEN_DATE) ASC) as sdrank
 FROM students_dates sd2
 ) where sdrank = 1) sd on sd.idstudent = s.idstudent