我使用的是SQL Server 2016,我的用户已多次从活动状态变为非活动状态。使用TSQL我的目标是为每个用户定义每个活动和非活动时段的开始和结束日期范围。这很重要,因为在以后的操作中,我仅限于基于活动时段应用的内容。下面列出的是几个表格,说明了我所寻求的内容和客观结果。结束日期的NULL表示此状态为当前状态,并使用GETDATE()解释为今天的日期。
给定:(假设此源表已命名," User_Activity")。
预期结果:
预先感谢您的协助。我搜索了其他相关问题但找不到任何东西。以下是用于创建上述源测试数据集的SQL。
CREATE TABLE #User_Activity (
UserID INT
,[Start] DATE
,[End] DATE
,[Status] VARCHAR(10) NULL)
INSERT INTO #User_Activity (UserID, [Start], [End], [Status])
SELECT 1, '1/1/2005', '9/5/2006', 'Active' UNION ALL
SELECT 1, '9/6/2006', '4/2/2007', 'Active' UNION ALL
SELECT 1, '4/3/2007', '12/31/2007', 'Inactive' UNION ALL
SELECT 2, '3/15/2009', '9/22/2009', 'Active' UNION ALL
SELECT 2, '9/23/2009', '12/31/2012', 'Active' UNION ALL
SELECT 2, '1/1/2013', '8/15/2013', 'Inactive' UNION ALL
SELECT 2, '8/16/2013', '5/31/2015', 'Inactive' UNION ALL
SELECT 2, '6/1/2015', '2/5/2017', 'Active' UNION ALL
SELECT 2, '2/6/2015', NULL, 'Active'
答案 0 :(得分:1)
虽然它不是最佳解决方案,但在此方案中可达到目的,请尝试以下操作:
DECLARE @USER_ACTIVITY TABLE (USERID INT, [START] DATE, [END] DATE, [STATUS] VARCHAR(10))
INSERT INTO @USER_ACTIVITY
SELECT 1, '1/1/2005', '9/5/2006', 'ACTIVE'
UNION ALL
SELECT 1, '9/6/2006', '4/2/2007', 'ACTIVE'
UNION ALL
SELECT 1, '4/3/2007', '12/31/2007', 'INACTIVE'
UNION ALL
SELECT 2, '3/15/2009', '9/22/2009', 'ACTIVE'
UNION ALL
SELECT 2, '9/23/2009', '12/31/2012', 'ACTIVE'
UNION ALL
SELECT 2, '1/1/2013', '8/15/2013', 'INACTIVE'
UNION ALL
SELECT 2, '8/6/2013', '5/31/2015', 'INACTIVE'
UNION ALL
SELECT 2, '6/1/2015', '2/5/2017', 'ACTIVE'
UNION ALL
SELECT 2, '2/6/2017', NULL, 'ACTIVE'
UPDATE @USER_ACTIVITY SET [END] = GETDATE() WHERE [STATUS] = 'ACTIVE' AND [END] IS NULL
;WITH CTE AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY USERID, [STATUS] ORDER BY [START], [END]) AS R1,
ROW_NUMBER() OVER (PARTITION BY USERID ORDER BY [START], [END]) AS R2
FROM @USER_ACTIVITY
)
SELECT USERID, MIN([START]) [START], MAX([END]) [END], [STATUS]
FROM CTE
GROUP BY USERID, [STATUS], R2-R1
ORDER BY USERID, [START]
HTH!
答案 1 :(得分:0)
我没有为完整数据集测试这个,因为我没有格式化所有这些日期,但是,这应该有效:
CREATE TABLE #User_Activity (
UserID INT
,[Start] DATE
,[End] DATE
,[Status] VARCHAR(10) NULL)
INSERT INTO #User_Activity (UserID, [Start], [End], [Status])
SELECT 1, '20050101', '20060905', 'Active' UNION ALL
SELECT 1, '20060906', '20070402', 'Active' UNION ALL
SELECT 1, '20070403', '20071231', 'Inactive';
GO
WITH Grp AS (
SELECT UserID,
[Start],
ISNULL([End], CONVERT(date, GETDATE())) AS [End],
[Status],
ROW_NUMBER() OVER (PARTITION BY UserID ORDER BY [Start]) -
ROW_NUMBER() OVER (PARTITION BY UserID, [Status] ORDER BY [Start]) AS Grp
FROM #User_Activity UA)
SELECT UserID,
MIN([Start]) AS MinStart,
MAX([End]) AS MaxEnd,
[Status]
FROM Grp
GROUP BY UserID, [Status], Grp;
GO
DROP TABLE #User_Activity;