【发布时间】:2019-05-16 15:44:04
【问题描述】:
情况:
我有三张桌子。表 1 有 ID 和订阅日期。表 2 包含 ID、活动状态和活动状态更改的最近日期。 表 3 包含 Id 和所有状态更改的日志。 注意: 在订阅日期,所有 ID 都处于活动状态。当一天内有多个状态变化时,选择最近的一个。
目标:
我需要计算出每天每种状态的 ID 数。 IE。每天有多少人活跃、不活跃和冒险。 我的问题是确保每天都计算 ID 的状态,即使在特定日期没有数据也是如此。例如: ID 1(见下面的小提琴)自 5 月 2 日(加入日期)以来一直处于活动状态,并且状态没有变化,所以到现在为止,他应该每天都被视为活动。
在其他地方咨询过这个问题后,有人提出创建函数和交叉应用并将计数存储在表中。我没有这样做的技能,但这是解决此问题的一种选择吗?
所需的输出:
+------------+----------+-------+
| date | status | count |
+------------+----------+-------+
| 1-May-2019 | active | 0 |
| 1-May-2019 | inactive | 0 |
| 1-May-2019 | risky | 1 |
| 2-May-2019 | active | 1 |
| 2-May-2019 | inactive | 0 |
| 2-May-2019 | risky | 1 |
| 3-May-2019 | active | 1 |
| 3-May-2019 | inactive | 0 |
| 3-May-2019 | risky | 1 |
| 4-May-2019 | active | 1 |
| 4-May-2019 | inactive | 0 |
| 4-May-2019 | risky | 1 |
| 5-May-2019 | active | 3 |
| 5-May-2019 | inactive | 0 |
| 5-May-2019 | risky | 1 |
| ... | ... | ... |
+------------+----------+-------+
小提琴:
--create date table (not sure if usable)
CREATE TABLE #dates ([date] date)
DECLARE @dIncr DATE = '2019-05-01'
DECLARE @dEnd DATE = dateadd(day,-1,getdate())
WHILE (@dIncr <= @dEnd)
BEGIN
INSERT INTO #dates ([date]) VALUES (@dIncr)
SELECT @dIncr = DATEADD(day,1,@dIncr)
END
GO
-- ID + Subscribed Date (starts active at joindate)
create table #t1 (id int, [subdate] date)
insert into #t1 values
(9, '2019-01-01'),
(1, '2019-05-02'),
(2, '2019-05-05'),
(3, '2019-05-05'),
(4, '2019-05-10')
GO
-- ID + Latest activity date
create table #t2 (id int, [status] varchar(max), [datestatus] date)
insert into #t2 values
(9,'risky', '2019-03-01'),
(1, 'active', '2019-05-02'),
(2, 'inactive', '2019-05-13'),
(3, 'active', '2019-05-14'),
(4, 'risky', '2019-05-15')
GO
-- ID + Activity Logs Date
create table #t3 (id int, [statuschange] varchar(max), [datechange] date)
insert into #t3 values
(9,'inactive', '2019-01-01'),
(9,'active', '2019-02-01'),
(9,'risky', '2019-03-01'),
(2, 'risky', '2019-05-08'),
(2, 'inactive', '2019-05-13'),
(3, 'inactive', '2019-05-08'),
(3, 'active', '2019-05-14'),
(4, 'inactive', '2019-05-15'),
(4, 'risky', '2019-05-15')
GO
我现在拥有的:
;with cte as (
select
#t1.id
,COALESCE(LAG(datechange) over(partition by #t1.id order by datechange),subdate) as StartDate
,#t3.datechange
,COALESCE(LAG(statuschange) over(partition by #t1.id order by datechange),'active') as PreviousStatusChange
,#t3.statuschange
from #t1
inner join #t2 on #t1.id=#t2.id
left join #t3 on #t1.id=#t3.id
)
select
cte.id
,cte.StartDate
,coalesce(cte.datechange,'2099-01-01') as EndDate
,PreviousStatusChange
,coalesce(statuschange,previousstatuschange) AS NewStatus
from cte
【问题讨论】:
-
使用日历和计数表。
-
@Larnu 我的小提琴里有它。但是如果没有我无法弄清楚的值,它的逻辑就是每天强制计数
-
您需要使用包含每个日期的日历表或计数表。问题的根源是您在查询中的基表需要每天都在其中。然后将每天的表加入到数据中,以便在计数为零时获得一行。
-
@Larnu 我看不出这个问题是如何重复的?我知道需要使用日期表。这里的问题是考虑状态变化。
-
发布示例数据、期望结果和当前尝试的工作非常棒!
标签: sql sql-server