如何根据用户的状态定义日期范围集

问题描述 投票:0回答:2

我正在使用SQL Server 2016,我的用户已经多次从活动状态变为非活动状态。使用TSQL我的目标是为每个用户定义每个活动和非活动时段的开始和结束日期范围。这很重要,因为在以后的操作中,我仅限于基于活动期间可以应用的内容。下面列出的是几个表格,说明了我所寻求的内容和客观结果。结束日期的NULL表示此状态为当前状态,并使用GETDATE()解释为今天的日期。

给定:(假设此源表名为“User_Activity”)。

Blockquote

预期结果:

Blockquote

提前感谢你的帮助。我搜索了其他相关问题但找不到任何东西。这是用于创建上述源测试数据集的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'
sql sql-server tsql
2个回答
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;

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!

© www.soinside.com 2019 - 2024. All rights reserved.