在行之间计算表内的日期差异[Postgresql]

时间:2013-10-07 18:28:23

标签: sql postgresql

这是一个非常简化的表,但过程应该是相同的。我想计算登录之间的天数。这是表设置查询。

create table tester (user_id int, login_day date);

insert into tester (user_id,login_day) 
values 
 (1,'2013-10-02'),
 (1,'2013-10-05'),
 (2,'2013-10-03'),
 (2,'2013-10-04'),
 (2,'2013-10-07');

这样做:

user_id; login_day
     1;  "2013-10-02"
     1;  "2013-10-05"
     2;  "2013-10-03"
     2;  "2013-10-04"
     2;  "2013-10-07"

结果表应如下所示:

user_id; login_day; tau
     1;"2013-10-02"; 2
     1;"2013-10-05"; 1 --see edit
     2;"2013-10-03"; 0
     2;"2013-10-04"; 2 
     2;"2013-10-07"; 0

其中tau是天数-1的差异。 User_id(1)在2日和5日登录。所以他们的tau值是2,因为登录之间是两天。

User_id(2)因连续几天登录而值为0。

由于没有时间过去,第7名得到0。如果更容易,也可以标记为-1。

非常感谢您的帮助。非常感谢。

修改 的 澄清。 User_id(1),2013-10-05的tau值为1,因为他们在将当天视为第7天时没有重新登录。 例如,如果有人没有重新登录,他们的tau值会不断增加。因此,由于user_id = 1最后一次登录于5日,因此他们当前的tau值为1,并且该值将持续增加1,因为他们每天都不会重新登录。 再次感谢 - 尤其是a_horse_with_no_name和Linger的快速回复并帮助我澄清问题

2 个答案:

答案 0 :(得分:3)

这几乎给出了正确答案:

select user_id, 
       login_day,
       lead(login_day) over (partition by user_id order by user_id) - login_day - 1 as tau
from tester
order by user_id, login_day;

输出:

user_id | login_day  | tau   
--------+------------+-------
1       | 2013-10-02 | 2     
1       | 2013-10-05 | (null)
2       | 2013-10-03 | 0     
2       | 2013-10-04 | 2     
2       | 2013-10-07 | (null)

由于我不理解规则,为什么对于user_id = 1,“last”登录生成2但是对于user_id 2,最后一次登录生成0我不太确定如何修复第二次登录的错误显示user_id = 1

答案 1 :(得分:1)

如果您不介意在结果中使用Null,那么您可以使用(SAMPLE):

SELECT m.user_id, m.login_day, m.login_day - 
(
   SELECT MAX(login_day) 
   FROM tester AS s 
   WHERE m.user_id = s.user_id 
   AND s.login_day < m.login_day
) - 1 AS DaysInBetween
FROM tester AS m

如果要检查Null并指定0,请使用以下(SAMPLE):

SELECT TopL.user_id, TopL.login_day,
       COALESCE(TopL.DaysInBetween, 0) As TotalD
FROM   (
         SELECT m.user_id, m.login_day, 
           m.login_day - 
           (
             SELECT MAX(login_day)
             FROM tester AS s 
             WHERE m.user_id = s.user_id 
             AND s.login_day < m.login_day
           ) - 1 AS DaysInBetween
         FROM tester AS m
       ) AS TopL
ORDER BY user_id, 
         login_day

这是另一个需要考虑的问题(SAMPLE):

SELECT TopL.user_id, TopL.login_day,
       CASE (COALESCE(TopL.DaysInBetween, 0)) WHEN '-1'
          THEN '0' ELSE COALESCE(TopL.DaysInBetween, 0) END
          As TotalD
FROM (
       SELECT m.user_id, m.login_day, 
         COALESCE(
         (
           SELECT MIN(login_day)
           FROM tester AS s 
           WHERE m.user_id = s.user_id 
           AND s.login_day > m.login_day
         )- m.login_day - 1, current_date - m.login_day-1)
         AS DaysInBetween
       FROM tester AS m
       ) AS TopL
ORDER BY user_id, 
         login_day