简体   繁体   English

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

[英]Get closest date to given date for a group of records

Hi guys I'm having problems with a sql query, look, this is my scenario: 嗨,大家好,我在使用SQL查询时遇到问题,这是我的情况:

I have an students table and a table where I store dates when students enter or leave the school, so I want to get the nearest date to a given date for every student, I can't find the way to do this. 我有一个学生表和一个用于存储学生入学或离校时的日期的表,因此我想为每个学生获取到给定日期的最接近日期,我找不到解决方法。

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  |

Students Table: 学生表:

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;

Dates Table: 日期表:

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;

Can anyone help me? 谁能帮我?

Thank you so much. 非常感谢。

Using the proprietary distinct on () is usually faster in Postgres than using window functions. 在Postgres中,使用专有的distinct on ()通常比使用窗口函数要快。

Building on Gordon's idea with the abs(): 用abs()建立戈登的想法:

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');

This can also be solved using a Window function: 这也可以使用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 SQLFiddle: http ://sqlfiddle.com/#!15/25fef/4

Use DATEDIFF to get difference between dates, get ABS value. 使用DATEDIFF获取日期之间的差,获取ABS值。 Then sort by ABS(DATEDIFF()) and get top record. 然后按ABS(DATEDIFF())排序并获得最高记录。

This is a bit tricky. 这有点棘手。 I think the best method is distinct on . 我认为最好的方法distinct on You don't describe the data in your question, but this is the idea: 您没有描述问题中的数据,但这是一个主意:

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

If i understood your request , this is the answer. 如果我理解您的要求,这就是答案。 It joins the students table with the students dates table after its RANKED and takes only the date nearest to your GIVEN_DATE. 它将RANKED之后的学生表与学生日期表结合在一起,并且仅采用最接近您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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM