2015-09-26 63 views
-1

嗨,你看,这是我的情景:获得最接近的日期给定日期的一组记录我有一个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; 

谁能帮助我?

非常感谢。

+2

请**编辑**您的问题,请添加表格定义,一些示例数据和基于该示例数据的预期输出。这将是完美的,如果你还可以创建一个http://sqlfiddle.com的例子 –

+0

对不起,我是新的,现在是职位确定? – ozat

回答

3

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

大厦戈登与ABS()的想法:

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:

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

这也可以使用窗口函数来解决http://sqlfiddle.com/#!15/25fef/4

+0

谢谢!@a_horse_with_no_name,我用了第一个查询 – ozat

1

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

+0

Postgres中没有'datediff()' –

+0

我知道如何获得给定日期的最近日期,但我不明白的是如何为一组记录执行 – ozat

1

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

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

如果我理解你的请求,这是答案。 它将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 
+0

有很多简单的方法来使用' row_number()'或'rank()'来解决这个问题。您可能想要考虑其他方法。 (提示:不需要“加入”。) –

+0

只要告诉我一个加入如果使用两个不同的表格就没有必要。如果我能够正确理解,日期表可以为每个学生提供更多的1条记录,并且他想按照日期加入最近记录的学生表 – sagi

+0

我向帖子中添加了一些数据,对不起! – ozat

相关问题