Sql 如何使用daterange计算最长连胜记录
我在sql server中有一个表,它由以下数据组成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
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