如何计算SQL Server中用户的连续输入

时间:2016-02-04 03:22:23

标签: sql sql-server

给出包含以下列的表:

  • UserId int,
  • DateEntered DateTime

数据:

1  | 2016-02-24
1  | 2016-02-23
1  | 2016-02-22
1  | 2016-02-20
2  | 2016-02-24
2  | 2016-02-14
3  | 2016-02-23
3  | 2016-02-22
3  | 2016-02-21
2  | 2016-01-30
2  | 2016-01-29
2  | 2016-01-28
2  | 2016-01-27
2  | 2016-01-26
2  | 2016-01-25

我想为每个用户返回最新的条目,并且从今天开始为特定用户返回。

案例1

  • 今天= 2016-02-24
  • userid = 1

  • 返回值= 3 //用户错过第21天,所以连胜是22-24

案例2

  • 今天= 2016-02-24
  • userid = 2

  • 返回值= 1 //即使用户有1/25 - 1/30的较长条纹,也不是他的最新连胜

案例3

  • 今天= 2016-02-24
  • userid = 3

  • 返回值= 0 //今天用户错过了。因此,他今天没有连续几天计算

有关如何在T-SQL中完成此操作的任何想法?

更新1

根据响应,我修改了给出的示例查询,如下所示:然而,第二列中返回的值始终只有1或0,即使数据显示存在更多连续日期。

select 
    a.UserId,
    sum(case when dayseq = '2016-02-01' then 1 else 0 end)
from
   (select 
        t.*,
        dateadd(day, 1 - row_number() over (partition by UserId order by DateCreated), DateCreated) as dayseq
   from 
       fa.User_Journal t) a
where 
    DateCreated <= '2016-02-01'
group by 
   a.UserId;

更新2

以下查询进一步说明了该问题。下面提供的解决方案几乎解决了这个问题

在这个查询中,我说明了&#34;应该&#34;在@EndDate值下发生。通过取消对@EndDate的期望赋值的注释,您可以看到查询未根据提供的案例返回所需的结果。

非常感谢任何帮助。

DECLARE @Temp TABLE
(
    UserId nvarchar(128),
    DateCreated Date
)

INSERT INTO @TEMP (UserId, DateCreated) values ('uid123', '2016-01-19');
INSERT INTO @TEMP (UserId, DateCreated) values ('uid123', '2016-01-24');
INSERT INTO @TEMP (UserId, DateCreated) values ('uid123', '2016-01-28');
INSERT INTO @TEMP (UserId, DateCreated) values ('uid123', '2016-01-29');
INSERT INTO @TEMP (UserId, DateCreated) values ('uid123', '2016-02-01');
INSERT INTO @TEMP (UserId, DateCreated) values ('uid123', '2016-02-02');
INSERT INTO @TEMP (UserId, DateCreated) values ('uid123', '2016-02-03');
INSERT INTO @TEMP (UserId, DateCreated) values ('uid123', '2016-02-07');
INSERT INTO @TEMP (UserId, DateCreated) values ('uid123', '2016-01-19');


DECLARE @EndDate Date
SET @EndDate = '2016-02-03' -- Should return 5, as they are 5 consecutive days since @EndDate
--SET @EndDate = '2016-02-02' -- Should return 4, as they are 4 consecutive days since @EndDate
--SET @EndDate = '2016-02-19' -- Should return 1, as they are 4 consecutive days since @EndDate
--SET @EndDate = '2016-02-18' -- Should return 0, as they are 0 consecutive days since @EndDate


SELECT a.UserId,
    SUM(CASE WHEN dayseq <= @EndDate then 1 else 0 end) -1 as FitStreak
from (select t.*,
                dateadd(day,
                        1 - row_number() over (partition by UserId order by DateCreated),
                        DateCreated) as dayseq
        from @Temp t
        ) a
where DateCreated <= @EndDate
group by a.UserId;  

1 个答案:

答案 0 :(得分:0)

我认为以下是您想要的:

"World"

这会从每个日期中减去一个序号,从0开始。然后将结果与“当前日期”进行比较 - 瞧,该值是初始序列的“当前日期”。

select t.UserId, sum(case when dayseq = '2014-02-24' then 1 else 0 end) from (select t.*, dateadd(day, row_number() over (partition by UserId order by DateEntered desc) - 1, DateEntered) as dayseq from t ) t where DateEntered <= '2014-02-24' group by t.UserId; 语句中的逻辑也可以在case中。但是,结果将过滤掉没有日期的用户。

注意两个重要的假设:

  • 日期上没有时间组件
  • 没有重复日期

这两个都可以轻松处理,但结果查询有点复杂。

编辑:

使用时间组件,截断值:

where

Here是一个说明固定代码的SQL小提琴。