这是SQL数据库数据:
UserTable
UserName | UserDate | UserCode
-------------------------------------------
user1 | 08-31-2014 | 232
user1 | 09-01-2014 | 232
user1 | 09-02-2014 | 0
user1 | 09-03-2014 | 121
user1 | 09-08-2014 | 122
user1 | 09-09-2014 | 0
user1 | 09-10-2014 | 144
user1 | 09-11-2014 | 166
user2 | 09-01-2014 | 177
user2 | 09-04-2014 | 188
user2 | 09-05-2014 | 199
user2 | 09-06-2014 | 0
user2 | 09-07-2014 | 155
如果[UserCode]不是零,则只计算连续天数(如果为结果)。 UserDate介于09-01-2014和09-11-2014之间。 仅在结果为2或更多时显示结果。
我希望我的sql查询返回的是:
UserName | StartDate | EndDate | Result
----------------------------------------------------------
user1 | 09-01-2014 | 09-03-2014 | 2
user1 | 09-08-2014 | 09-11-2014 | 3
user2 | 09-04-2014 | 09-07-2014 | 3
这只能使用SQL查询吗?
答案 0 :(得分:20)
这是一个Gaps and Islands问题。解决此问题的最简单方法是使用ROW_NUMBER()
来确定序列中的间隙:
SELECT UserName,
UserDate,
UserCode,
GroupingSet = DATEADD(DAY,
-ROW_NUMBER() OVER(PARTITION BY UserName
ORDER BY UserDate),
UserDate)
FROM UserTable;
这给出了:
UserName | UserDate | UserCode | GroupingSet
------------+---------------+------------+-------------
user1 | 09-01-2014 | 1 | 08-31-2014
user1 | 09-02-2014 | 0 | 08-31-2014
user1 | 09-03-2014 | 1 | 08-31-2014
user1 | 09-08-2014 | 1 | 09-04-2014
user1 | 09-09-2014 | 0 | 09-04-2014
user1 | 09-10-2014 | 1 | 09-04-2014
user1 | 09-11-2014 | 1 | 09-04-2014
user2 | 09-01-2014 | 1 | 08-31-2014
user2 | 09-04-2014 | 1 | 09-02-2014
user2 | 09-05-2014 | 1 | 09-02-2014
user2 | 09-06-2014 | 0 | 09-02-2014
user2 | 09-07-2014 | 1 | 09-02-2014
正如您所看到的,这为连续行的GroupingSet
提供了一个常量值。然后,您可以按此列分组以获得所需的摘要:
WITH CTE AS
( SELECT UserName,
UserDate,
UserCode,
GroupingSet = DATEADD(DAY,
-ROW_NUMBER() OVER(PARTITION BY UserName
ORDER BY UserDate),
UserDate)
FROM UserTable
)
SELECT UserName,
StartDate = MIN(UserDate),
EndDate = MAX(UserDate),
Result = COUNT(NULLIF(UserCode, 0))
FROM CTE
GROUP BY UserName, GroupingSet
HAVING COUNT(NULLIF(UserCode, 0)) > 1
ORDER BY UserName, StartDate;
<强> Example on SQL Fiddle 强>
答案 1 :(得分:0)
请尝试:
;with T1 as(
select
*,
ROW_NUMBER() over ( order by UserName, UserDate) ID
from tbl
)
,T as (
SELECT *, 1 CNT FROM T1 where ID=1
union all
SELECT b.*, (case when T.UserDate+1=b.UserDate and
T.UserName=b.UserName then t.CNT
else T.CNT+1 end)
from T1 b INNER JOIN T on b.ID=T.ID+1
)
select distinct UserName, MIN(UserDate), max(UserDate)
,sum(case UserCode when 0 then 0 else 1 end) From T group by UserName, CNT
having COUNT(*)>1