我在myTable
中有此数据:
Date Status PersonID
-----------------------------------------
2018/01/01 2 2015 ┐ 2
2018/01/02 2 2015 ┘
2018/01/05 2 2015 ┐
2018/01/06 2 2015 3
2018/01/07 2 2015 ┘
2018/01/11 2 2015 - 1
2018/01/01 2 1018 - 1
2018/01/03 2 1018 - 1
2018/01/05 2 1018 ┐ 2
2018/01/06 2 1018 ┘
2018/01/08 2 1018 ┐ 2
2018/01/09 2 1018 ┘
2018/01/03 2 1625 ┐
2018/01/04 2 1625 4
2018/01/05 2 1625
2018/01/06 2 1625 ┘
2018/01/17 2 1625 - 1
2018/01/29 2 1625 - 1
-----------------------------------
并且我需要像这样计算连续的重复值:
这是我需要的结果:
count personid
-----------------
2 2015
3 2015
1 2015
1 1018
1 1018
2 1018
2 1018
4 1625
1 1625
1 1625
我正在使用SQL Server 2016-请帮助
答案 0 :(得分:2)
这是一个“ 差距和岛屿”问题,您可以尝试按照以下步骤进行操作。
;with cte
as (select *,
dateadd(day, -row_number()
over (partition by status, personid
order by [date] ), [date]) AS grp
FROM @table
)
,cte1
AS (select *,row_number() over(partition by personid, grp,status order by [date]) rn,
count(*) over(partition by personid, grp) ct
from cte
)
select ct as count, personid
from cte1
where rn=1
注意:由于没有任何可用于排序所需输出中显示方式的列,您可能无法以相同的顺序获得行。
答案 1 :(得分:2)
这是最简单和小的查询
CREATE TABLE #T (
[Date] date,
[Status] int,
PersonId int
);
INSERT #T
VALUES ('2018/01/01', 2, 2015),
('2018/01/02', 2, 2015),
('2018/01/05', 2, 2015),
('2018/01/06', 2, 2015),
('2018/01/07', 2, 2015),
('2018/01/11', 2, 2015),
('2018/01/01', 2, 1018),
('2018/01/03', 2, 1018),
('2018/01/05', 2, 1018),
('2018/01/06', 2, 1018),
('2018/01/08', 2, 1018),
('2018/01/09', 2, 1018),
('2018/01/03', 2, 1625),
('2018/01/04', 2, 1625),
('2018/01/05', 2, 1625),
('2018/01/06', 2, 1625),
('2018/01/17', 2, 1625),
('2018/01/29', 2, 1625)
SELECT
MAX(cnt),
personid
FROM (SELECT
ROW_NUMBER() OVER (PARTITION BY GRP ORDER BY [Date]) AS cnt,
personid,
GRP
FROM (SELECT
personid,
[Date],
DATEDIFF(DAY, '1900-01-01', [Date]) - ROW_NUMBER() OVER (ORDER BY Personid DESC) AS GRP
FROM #T) A) AS B
GROUP BY personid,
GRP
ORDER BY PersonId DESC
答案 2 :(得分:0)
WITH T1 AS
(SELECT Date,
Date - ROW_NUMBER() OVER (PARTITION BY Status, PersonID ORDER BY Date) AS Grp
FROM myTable)
SELECT personid,
ROW_NUMBER() OVER (PARTITION BY Grp ORDER BY Date) AS Consecutive
FROM T1
在此结果上,您可以应用MAX()
,以获取每个人证的记录数。
请参阅this问题以获取细分详细信息
答案 3 :(得分:0)
要找出两个日期之间的差距并就每个日期而言,您可以使用row_number()
分析函数和datediff
函数来创建该差距
with cte as
(
select '2018-01-01' as d, 2 as id , 2015 as pid
union all
select '2018-01-02',2,2015
union all
select '2018-01-05',2,2015 union all
select '2018-01-06',2,2015 union all
select '2018-01-07',2,2015
union all
select '2018-01-11',2,2015
), cte1 as (SELECT *,
datediff(day, Row_number()
OVER (
partition BY id, pid
ORDER BY [d] ), [d]) AS dif
FROM cte
) select distinct pid,count(*) over(partition by pid,dif) as cnt from cte1
答案 4 :(得分:0)
这种类型的问题称为“ 差距和岛屿”。您正在标识连续的数据集(孤岛)或两个孤岛之间的值范围(间隙)。有许多不同的方法来获得结果,这些方法在大型数据集上也能很好地执行。您可以参考以下写得很好的文章。
https://www.itprotoday.com/sql-server/solving-gaps-and-islands-enhanced-window-functions
https://www.red-gate.com/simple-talk/sql/t-sql-programming/the-sql-of-gaps-and-islands-in-sequences/
这是您尝试提出的问题。
CREATE TABLE #test
(
dt DATETIME
,Status INT
,PersonID INT
)
INSERT INTO #Test (dt, Status, PersonID) VALUES
('2018/01/01', 2, 2015),
('2018/01/02', 2, 2015),
('2018/01/05', 2, 2015),
('2018/01/06', 2, 2015),
('2018/01/07', 2, 2015),
('2018/01/11', 2, 2015),
('2018/01/01', 2, 1018),
('2018/01/03', 2, 1018),
('2018/01/05', 2, 1018),
('2018/01/06', 2, 1018),
('2018/01/08', 2, 1018),
('2018/01/09', 2, 1018),
('2018/01/03', 2, 1625),
('2018/01/04', 2, 1625),
('2018/01/05', 2, 1625),
('2018/01/06', 2, 1625),
('2018/01/17', 2, 1625),
('2018/01/29', 2, 1625)
;with cte_dt_from
AS
(
SELECT PersonID, MIN(Dt) dt_from_start
FROM #Test
GROUP BY PersonID
),
cte_offset_num
AS
(
SELECT T1.PersonID, T1.dt, DATEDIFF(DAY, T2.dt_from_start, T1.dt) dt_offset
FROM #test T1
INNER JOIN cte_dt_from T2 ON T2.PersonID = T1.PersonID
),
cte_starting_point
AS
(
SELECT A.PersonID, A.dt_offset, ROW_NUMBER() OVER(PARTITION BY A.PersonID ORDER BY A.dt_offset) AS rownum
FROM cte_offset_num AS A
WHERE NOT EXISTS (
SELECT *
FROM cte_offset_num AS B
WHERE B.PersonID = A.PersonID AND B.dt_offset = A.dt_offset - 1)
)
,
cte_ending_point
AS
(
SELECT A.PersonID, A.dt_offset, ROW_NUMBER() OVER(PARTITION BY A.PersonID ORDER BY A.dt_offset) AS rownum
FROM cte_offset_num AS A
WHERE NOT EXISTS (
SELECT *
FROM cte_offset_num AS B
WHERE B.PersonID = A.PersonID AND B.dt_offset = A.dt_offset + 1)
)
SELECT (E.dt_offset - S.dt_offset) + 1 AS [count], S.PersonID
FROM cte_starting_point AS S
JOIN cte_ending_point AS E ON E.PersonID = S.PersonID AND E.rownum = S.rownum
ORDER BY S.PersonID;
DROP TABLE #Test;