给定以下数据:
create table #histories
(
username varchar(10),
account varchar(10),
assigned date
);
insert into #histories
values
('PHIL','ACCOUNT1','2017-01-04'),
('PETER','ACCOUNT1','2017-01-15'),
('DAVE','ACCOUNT1','2017-03-04'),
('ANDY','ACCOUNT1','2017-05-06'),
('DAVE','ACCOUNT1','2017-05-07'),
('FRED','ACCOUNT1','2017-05-08'),
('JAMES','ACCOUNT1','2017-08-05'),
('DAVE','ACCOUNT2','2017-01-02'),
('PHIL','ACCOUNT2','2017-01-18'),
('JOSH','ACCOUNT2','2017-04-08'),
('JAMES','ACCOUNT2','2017-04-09'),
('DAVE','ACCOUNT2','2017-05-06'),
('PHIL','ACCOUNT2','2017-05-07') ;
...表示将给定用户分配给帐户的时间。
我正在寻找在每个月的最后一天确定谁拥有给定帐户(指定日期是帐户转移所有权的日期),并填充任何缺少的月末dates
(可能是从我可用的方便表创建的,带有有用的列DateKey
,Date
和LastDayOfMonth
, [@AaronBertrand 提供]) 1。
期望的结果是:
PETER, ACCOUNT1, 2017-01-31
PETER, ACCOUNT1, 2017-02-28
DAVE, ACCOUNT1, 2017-03-31
DAVE, ACCOUNT1, 2017-04-30
FRED, ACCOUNT1, 2017-05-31
FRED, ACCOUNT1, 2017-06-30
FRED, ACCOUNT1, 2017-07-31
JAMES, ACCOUNT1, 2017-08-31
PHIL, ACCOUNT2, 2017-01-31
PHIL, ACCOUNT2, 2017-02-28
PHIL, ACCOUNT2, 2017-03-31
JAMES, ACCOUNT2, 2017-04-30
PHIL, ACCOUNT2, 2017-05-31
使用窗口函数执行此操作的初始部分是微不足道的,它添加了我正在努力解决的“缺失”行。
解决此问题的一种方法是执行以下操作:
LEAD
在 SQL Server 2008 上进行仿真。您可以APPLY
为此使用或 suquery。我稍微修改了您的测试数据以使结果具有确定性。还添加了一个索引:
这是有史以来最懒惰的日期维度表:
For step 1, there are plenty of ways to emulate
LEAD
. Here's one method:For step 2, we need to change the NULL values to something else. You want to include the final month for each account, so adding one month to the starting date suffices:
For step 3, we can join to the date dimension table. The column from the dimension table is exactly the column you need for the result set:
I didn't like the query that I got when I put it all together. There can be issues with join order when combining
OUTER APPLY
andINNER JOIN
. To get the join order I wanted I rewrote it with a subquery:I don't know how much data you have so it might not matter for you. But the plan looks how I want it to:
The results match yours:
这里我不使用日历表,而是使用自然数表 nums.dbo.nums (希望你也有,如果没有,也可以轻松生成)
我的答案与您的答案略有不同('JOSH' <-> 'JAMES'),因为您的数据包含以下 2 行:
使用相同的帐户和指定的日期,并且您没有准确说明在这种情况下应该采取哪一个。
三角加入为胜利!
结果是:
交互式执行计划在这里。
I/O 和 TIME 统计信息(在逻辑读取后截断所有零值):
查询以创建所需的“临时表”并测试我建议的 T-SQL 语句:
这绝不是一个看起来很干净的解决方案,但它似乎提供了您正在寻找的结果(我相信其他人会为您提供漂亮、干净、完全优化的查询)。
我使用了Aaron Bertrand 的日期维度表,正如您在问题中提到的那样(对于这种情况,这是一个超级方便的表),我编写了以下代码:
我使用以下代码将
EndOfMonth
列添加到#dim
表中(列之后):FirstOfMonth
和解决方案: