2016-11-09 63 views
0

假设我有一个日记表。日记中的每个条目都有一个user_id和一个entry_date。 对于user_id的范围,我想选择晚于指定日期的第一个条目。对于所有行,选择满足条件的第一个条目

因此,与

user_id | entry_date 
-------------------- 
    1  | 2016-11-09 20:00:00 
    2  | 2016-11-09 20:00:00 
    1  | 2016-11-09 21:00:00 
    1  | 2016-11-09 22:00:00 
    5  | 2016-11-10 20:00:00 

我想我可以写类似

SELECT user_id,entry_date FROM entries 
WHERE entries.user_id BETWEEN 10 AND 20 
AND TAKE_FIRST(entries.entry_date >= to_timestamp('2016-11-09 20:30:00', 'yyyy-mm-dd hh24:mi:ss')) 

(其中TAKE_FIRST()是什么我不知道的占位符。)

这样的结果将是

user_id | entry_date 
-------------------- 
    1  | 2016-11-09 21:00:00 
    5  | 2016-11-10 20:00:00 

我该如何做到这一点?

回答

1

随着ROW_NUMBER()

SELECT user_id,entry_date 
FROM (
    SELECT user_id,entry_date, 
      ROW_NUMBER() OVER(PARTITION BY user_id ORDER BY entry_date) as rnk 
    FROM entries 
    WHERE entries.user_id BETWEEN 10 AND 20 
     AND entries.entry_date >= to_timestamp('2016-11-09 20:30:00', 'yyyy-mm-dd hh24:mi:ss') 
    ) 
WHERE rnk = 1 
+0

我想有一个性能问题,所有时间戳大于指定的日期将被选中,并从那里只选择1。表现能够得到改善吗? – kasperhj

2
SELECT user_id,MIN(entry_date) FROM entries 
WHERE entries.user_id BETWEEN 10 AND 20 
AND entry_date >= to_timestamp('2016-11-09 20:30:00', 'yyyy-mm-dd hh24:mi:ss')) 
GROUP BY user_id 

对于范围内的每个USER_ID发现最小日期比你更大的选择。如果您需要entries表中的其他数据,它将无法工作,否则应该是最简单的解决方案。

+0

好的眼睛看到它可以解决没有窗口功能,+1。这就是说,如果他想要更多的列,那么它不会做:) – sagi

+0

@sagi - 如果他想要更多的列,它会做得很好,这就是'keep(dense_rank first/last order by entry_date)'是for! – mathguy

+0

是的,如果他将使用窗口函数,它看起来像OP知道怎么做它?我只是说,如果需要从第一个条目更多的列,那么代码将不会工作。 @mathguy – sagi