Sql 如何使用daterange计算最长连胜记录

Sql 如何使用daterange计算最长连胜记录,sql,sql-server-2008,Sql,Sql Server 2008,我在sql server中有一个表,它由以下数据组成 userID amount startdate enddate game Result ------------------------------------------------------------------------------- 68838 51.00 2014-05-29 15:41:41.167 2014-05-29 15:41:41.167 1 W 6883

我在sql server中有一个表,它由以下数据组成

userID  amount  startdate              enddate        game    Result
-------------------------------------------------------------------------------
68838   51.00   2014-05-29 15:41:41.167 2014-05-29 15:41:41.167 1   W
68838   51.00   2014-05-29 15:42:30.757 2014-05-29 15:42:30.757 1   W
68838   -0.50   2014-05-31 16:57:31.033 2014-05-31 16:57:31.033 1   L
68838   -0.50   2014-05-31 17:05:31.023 2014-05-31 17:05:31.023 1   L
68838   -0.50   2014-05-31 17:22:03.857 2014-05-31 17:22:03.857 1   L
68838   0.42    2014-05-31 17:26:32.570 2014-05-31 17:26:32.570 1   W
68838   0.42    2014-05-31 17:34:45.330 2014-05-31 17:34:45.330 1   W
68838   0.42    2014-05-31 17:38:44.107 2014-05-31 17:38:44.107 1   W
68838   0.42    2014-05-31 17:42:12.790 2014-05-31 17:42:12.790 1   W
434278  0.42    2014-05-31 16:57:31.033 2014-05-31 16:57:31.033 1   W
434278  0.42    2014-05-31 17:05:31.023 2014-05-31 17:05:31.023 1   W
434278  0.42    2014-05-31 17:22:03.857 2014-05-31 17:22:03.857 1   W
434278  -0.50   2014-05-31 17:26:32.570 2014-05-31 17:26:32.570 1   L
434278  -0.50   2014-05-31 17:34:45.330 2014-05-31 17:34:45.330 1   L
434278  -0.50   2014-05-31 17:38:44.107 2014-05-31 17:38:44.107 1   L
434278  -0.50   2014-05-31 17:42:12.790 2014-05-31 17:42:12.790 1   L
434278  0.42    2014-05-31 17:46:40.723 2014-05-31 17:46:40.723 1   W
434278  -0.50   2014-05-31 17:51:26.190 2014-05-31 17:51:26.190 1   L
434278  0.42    2014-05-31 17:55:32.870 2014-05-31 17:55:32.870 1   W
434278  -4.00   2014-05-31 18:06:54.937 2014-05-31 18:06:54.937 1   L
434278  -2.00   2014-05-31 18:19:29.483 2014-05-31 18:19:29.483 1   L
我希望结果如下所示,为每个用户显示最长的连胜记录

UserId StartDate                  Enddate                    Streak  amount
--------------------------------------------------------------------
68838  2014-05-31 17:26:32:570    2014-05-31 17:42:12:570     4       1.68
434278  2014-05-31 16:57:31:033   2014-05-31 17:22:03:857     3       1.26

以下是一些让你开始的想法。您可以使用内部查询并开始解决问题。基本上,它首先向每一行添加一个额外的列来显示前面的结果。然后,每次以前的结果不同于当前的结果,考虑它是一个组交换机。每个分组都有自己的数字0,并且在用户id的上下文中。扔掉“L”分组。现在,您对每个用户的最大计数分组感兴趣

SELECT *
      ,COUNT(grouping) OVER (PARTITION BY userid, grouping
                 ORDER BY startdate
                 ROWS BETWEEN UNBOUNDED PRECEDING
                      AND UNBOUNDED FOLLOWING ) as max_group_count

  FROM ( SELECT *
           ,SUM(CASE WHEN result <> prev_result THEN 1 ELSE 0 END) OVER
           (PARTITION BY userid ORDER BY startdate) AS grouping

       FROM ( SELECT *
            ,COALESCE(LAG(result) OVER
                (PARTITION BY userid ORDER BY startdate), result) AS prev_result
            FROM game
        ) x

       WHERE result = 'W'

       ) y
免责声明:Glenn的回答是一个很好的回答,为您带来了很多麻烦,但它并没有完全满足您的要求。我本来打算发布一个我一直在研究的答案,但当我添加它时,我发现格伦做举重的方式比我做举重的方式好,所以我修改了我的答案,加入了他的方式。我劝你接受他的回答,而不是我的

下面的内容应该完全符合您的要求

SELECT
    Userid,
    Min_StartDate as StartDate,
    Max_EndDate as EndDate,
    max_group_count as Streak,
    sum_Amount as Amount

FROM (
    SELECT
        *,
        -- we want the earliest maximum streak
        max(Min_StartDate) OVER (PARTITION BY userid) as Earliest_StartDate

    FROM (
        SELECT
            *,
            -- we want the maximum streak
            max(max_group_count) OVER (PARTITION BY userid) as MAX_Streak
        FROM (    
            SELECT DISTINCT
                  userid,
                  -- Calculate this streak
                  COUNT(grouping) OVER (PARTITION BY userid, grouping
                             ORDER BY startdate
                             ROWS BETWEEN UNBOUNDED PRECEDING
                                  AND UNBOUNDED FOLLOWING ) as max_group_count
                  -- Calcualte the start date of this streak
                  ,MIN(StartDate) OVER (PARTITION BY userid, grouping
                             ORDER BY startdate
                             ROWS BETWEEN UNBOUNDED PRECEDING
                                  AND UNBOUNDED FOLLOWING ) as Min_StartDate
                  -- Calcualte the end date of this streak
                  ,MAX(EndDate) OVER (PARTITION BY userid, grouping
                             ORDER BY startdate
                             ROWS BETWEEN UNBOUNDED PRECEDING
                                  AND UNBOUNDED FOLLOWING ) as Max_EndDate
                  -- Calcualte the total amount
                  ,SUM(Amount) OVER (PARTITION BY userid, grouping
                             ORDER BY startdate
                             ROWS BETWEEN UNBOUNDED PRECEDING
                                  AND UNBOUNDED FOLLOWING ) as Sum_Amount         

              FROM ( SELECT *
                        -- Assign a group number to the streak, so we can group by it
                       ,SUM(CASE WHEN result <> prev_result THEN 1 ELSE 0 END) OVER
                       (PARTITION BY userid ORDER BY startdate) AS grouping

                   FROM ( SELECT *
                         -- We want to look at the previous record to determin when the 
                         -- winning/loosing streak starts and ends
                        ,COALESCE(LAG(result) OVER
                            (PARTITION BY userid ORDER BY startdate), result) AS prev_result
                        FROM game
                    ) a

                   WHERE result = 'W'

                   ) b
             ) c
      ) d 
  WHERE
      Max_Group_Count = Max_Streak

) e
WHERE
  Min_StartDate = Earliest_StartDate
我已经把它作为一个sql提琴,如果您愿意的话可以使用它:

在SQLServer2008中,SUM不可能使用overorderby…,这使得查询稍微复杂一些,但并非不可能

;WITH myID AS (
  SELECT userID, amount, startdate, enddate, game, Result
       , ID = Row_Number() OVER (Partition By userID ORDER BY startdate)
  FROM   Table1 t1
), SR AS (
  SELECT t1.userID, t1.startdate, t1.enddate, t1.Result, t1.amount
       , SUM(CASE WHEN t1.Result <> COALESCE(t2.Result, t1.Result) 
                  THEN 1 
                  ELSE 0 END) SC
  FROM   myID t1
         LEFT JOIN myID t2 ON t1.userID = t2.userID AND t1.ID >= t2.ID
  GROUP BY t1.userID, t1.startdate, t1.enddate, t1.Result, t1.amount
), SL AS (
  SELECT userID, Result, SC, Count(1) Streak
       , Row_Number() OVER (PARTITION BY userID ORDER BY Count(1) DESC) Pos
  FROM   SR
  WHERE  Result = 'W'
  GROUP BY userID, Result, SC
)
SELECT p.userID
     , MIN(p.startdate) startdate
     , MAX(p.enddate) enddate
     , l.Streak
     , SUM(p.Amount) Amount
FROM   SR p
       INNER JOIN SL l ON p.userID = l.userID AND p.SC = l.SC
WHERE  l.Pos = 1
GROUP BY p.userID, l.Streak
myID CTE为数据生成一个整数ID,以简化下一个CTE的连接条件,如果问题中显示的数据不是整个表,并且已经有一列具有相同效果,则应删除此CTE。 SR StreakRank CTE将条纹计数器SC添加到数据中,使用三角形连接为每个条纹生成一个秩,它不是密集秩,只是用来分组的东西。 SL StreakLength CTE获取每个连胜的连胜长度,并根据长度创建位置排名。
主查询综合起来:从SL获取每次使用的最长条纹,并将其加入SR以获取详细信息。

+1有趣的问题,认为结果集中的结束日期不正确。68838用户我前面没有SQL Server,所以我无法测试,但我的第一种方法是找到每个玩家的最后一次损失,尝试最大可能,然后计算在损失时间后有多少胜利?这将给出当前连胜,认为op正在寻找最长的连胜。Nikhil你能澄清一下吗?明白了。那是的,那不行。用新的数量编辑了我的答案column@StormCould:这将适用于SQL Server 2012及更高版本,因为在Server 2012中引入了滞后和“无界前后行之间的行”。你能分享一个同样在2008服务器上运行的查询吗。提前谢谢你忘了包括金额栏?????请包括金额栏,否则它将起作用fine@nikhilshrma对不起!我已经添加了amount列,并为您更新了sqlfiddle。希望有帮助
| USERID |                  STARTDATE |                    ENDDATE | STREAK | AMOUNT |
|--------|----------------------------|----------------------------|--------|--------|
|  68838 | May, 31 2014 17:26:32+0000 | May, 31 2014 17:42:12+0000 |      4 |   1.68 |
| 434278 | May, 31 2014 16:57:31+0000 | May, 31 2014 17:22:03+0000 |      3 |   1.26 |
;WITH myID AS (
  SELECT userID, amount, startdate, enddate, game, Result
       , ID = Row_Number() OVER (Partition By userID ORDER BY startdate)
  FROM   Table1 t1
), SR AS (
  SELECT t1.userID, t1.startdate, t1.enddate, t1.Result, t1.amount
       , SUM(CASE WHEN t1.Result <> COALESCE(t2.Result, t1.Result) 
                  THEN 1 
                  ELSE 0 END) SC
  FROM   myID t1
         LEFT JOIN myID t2 ON t1.userID = t2.userID AND t1.ID >= t2.ID
  GROUP BY t1.userID, t1.startdate, t1.enddate, t1.Result, t1.amount
), SL AS (
  SELECT userID, Result, SC, Count(1) Streak
       , Row_Number() OVER (PARTITION BY userID ORDER BY Count(1) DESC) Pos
  FROM   SR
  WHERE  Result = 'W'
  GROUP BY userID, Result, SC
)
SELECT p.userID
     , MIN(p.startdate) startdate
     , MAX(p.enddate) enddate
     , l.Streak
     , SUM(p.Amount) Amount
FROM   SR p
       INNER JOIN SL l ON p.userID = l.userID AND p.SC = l.SC
WHERE  l.Pos = 1
GROUP BY p.userID, l.Streak