mhs*_*kar 3 sql sql-server sql-server-2016
我有一个具有以下结构的表
ID PersonID Date
---------------------------
1 1 2017-04-01
2 1 2017-04-15
3 1 2017-05-13
4 1 2017-06-15
5 1 2017-08-13
6 1 2017-10-02
7 2 2017-05-04
8 2 2017-09-16
9 3 2017-04-23
10 3 2017-07-06
11 4 2017-06-01
Run Code Online (Sandbox Code Playgroud)
如果存在,我希望Select在每个Next和Previous行之间2017-05-01和之间行.2017-08-26PersonID
我想要这个结果:
ID PersonID Date
------------------------------
2 1 2017-04-15
3 1 2017-05-13
4 1 2017-06-15
5 1 2017-08-13
6 1 2017-10-02
7 2 2017-05-04
8 2 2017-09-16
9 3 2017-04-23
10 3 2017-07-06
11 4 2017-06-01
Run Code Online (Sandbox Code Playgroud)
请尝试以下查询
create table TestData(ID int,PersonID int,[Date] date)
insert TestData(ID,PersonID,[Date])values
(1 ,1,'20170401'),(2 ,1,'20170415'),(3 ,1,'20170513'),
(4 ,1,'20170615'),(5 ,1,'20170813'),(6 ,1,'20171002'),
(7 ,2,'20170504'),(8 ,2,'20170916'),(9 ,3,'20170423'),
(10,3,'20170706'),(11,4,'20170601')
----------------
DECLARE
@FromDate date='20170501',
@ToDate date='20170826'
SELECT *
FROM
(
SELECT
*,
LAG(IIF([Date] BETWEEN @FromDate AND @ToDate,1,0))OVER(PARTITION BY PersonID ORDER BY [Date],ID) LagOK,
LEAD(IIF([Date] BETWEEN @FromDate AND @ToDate,1,0))OVER(PARTITION BY PersonID ORDER BY [Date],ID) LeadOK
FROM TestData
) q
WHERE ([Date] BETWEEN @FromDate AND @ToDate OR LagOK=1 OR LeadOK=1)
Run Code Online (Sandbox Code Playgroud)
带CTE和的变体ROW_NUMBER
;WITH numCTE AS(
SELECT
*,
ROW_NUMBER()OVER(PARTITION BY PersonID ORDER BY [Date],ID) N
FROM TestData
)
SELECT n.*
FROM
(
SELECT PersonID,MIN(N)-1 MinN,MAX(N)+1 MaxN
FROM numCTE
WHERE [Date] BETWEEN @FromDate AND @ToDate
GROUP BY PersonID
) q
JOIN numCTE n on n.PersonID=q.PersonID AND n.N BETWEEN q.MinN AND q.MaxN
Run Code Online (Sandbox Code Playgroud)
我也为这种情况添加了新的测试数据和修改过的查询
create table TestData(ID int,PersonID int,[Date] date)
insert TestData(ID,PersonID,[Date])values
(1 ,1,'20170401'),(2 ,1,'20170415'),(3 ,1,'20170513'),
(4 ,1,'20170615'),(5 ,1,'20170813'),(6 ,1,'20171002'),
(7 ,2,'20170504'),(8 ,2,'20170916'),(9 ,3,'20170423'),
(10,3,'20170706'),(11,4,'20170601'),
(14,6,'20170415'),(15,6,'20170913'),(16,6,'20171015') -- new test data
DECLARE
@FromDate date='20170501',
@ToDate date='20170826'
SELECT *
FROM
(
SELECT
*,
LAG(IIF([Date] BETWEEN @FromDate AND @ToDate,1,0))OVER(PARTITION BY PersonID ORDER BY [Date],ID) LagOK,
LEAD(IIF([Date] BETWEEN @FromDate AND @ToDate,1,0))OVER(PARTITION BY PersonID ORDER BY [Date],ID) LeadOK
FROM
(
SELECT ID,PersonID,[Date]
FROM TestData
UNION ALL
SELECT DISTINCT NULL,PersonID,@FromDate -- add phantom rows for some people
FROM TestData p
WHERE NOT EXISTS(SELECT * FROM TestData d WHERE d.[Date] BETWEEN @FromDate AND @ToDate AND d.PersonID=p.PersonID)
) q
) q
WHERE ([Date] BETWEEN @FromDate AND @ToDate OR LagOK=1 OR LeadOK=1)
AND ID IS NOT NULL -- exclude phantom rows from result
Run Code Online (Sandbox Code Playgroud)
以及CTE和ROW_NUMBER的新变种
;WITH numCTE AS(
SELECT
*,
ROW_NUMBER()OVER(PARTITION BY PersonID ORDER BY [Date],ID) N
FROM
(
SELECT ID,PersonID,[Date]
FROM TestData
UNION ALL
SELECT DISTINCT NULL,PersonID,@FromDate -- add phantom rows for some people
FROM TestData p
WHERE NOT EXISTS(SELECT * FROM TestData d WHERE d.[Date] BETWEEN @FromDate AND @ToDate AND d.PersonID=p.PersonID)
) q
)
SELECT n.*
FROM
(
SELECT PersonID,MIN(N)-1 MinN,MAX(N)+1 MaxN
FROM numCTE
WHERE [Date] BETWEEN @FromDate AND @ToDate
GROUP BY PersonID
) q
JOIN numCTE n on n.PersonID=q.PersonID AND n.N BETWEEN q.MinN AND q.MaxN
WHERE ID IS NOT NULL -- exclude phantom rows from result
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
144 次 |
| 最近记录: |