Mar*_*man 13 sql-server optimization sql-server-2012 date
图片在部门之间转移的服务台票。我们想知道在票打开的每一天,每个票在一天结束时的部门是什么。该表包含每张票的最后一个部门,在该部门发生变化的每一天开放(包括该票最初打开日期和关闭日期的一行)。数据表如下所示:
CREATE TABLE TicketAssigment (
TicketId INT NOT NULL,
AssignedDate DATE NOT NULL,
DepartmentId INT NOT NULL);
Run Code Online (Sandbox Code Playgroud)
我需要的是使用按日期排序的前一个 TicketAssigment 行中的 DepartmentId 为每个 TicketId 填写任何缺失的日期。
如果我有像这样的 TicketAssigment 行:
1, '1/1/2016', 123 -- Opened
1, '1,4,2016', 456 -- Transferred and closed
2, '1/1/2016', 25 -- Opened
2, '1/2/2016', 52 -- Transferred
2, '1/4/2016', 25 -- Transferred and closed
Run Code Online (Sandbox Code Playgroud)
我想要这个输出:
1, '1/1/2016', 123
1, '1/2/2016', 123
1, '1/3/2016', 123
1, '1/4/2016', 456
2, '1/1/2016', 25
2, '1/2/2016', 52
2, '1/3/2016', 52
2, '1/4/2016', 25
Run Code Online (Sandbox Code Playgroud)
这看起来可能接近我所需要的,但我没有耐心让它完成,并且估计的计划成本有 6 位数字:
SELECT l.TicketId, c.Date, MIN(l.DepartmentId)
FROM dbo.Calendar c
OUTER APPLY (SELECT TOP 1 TicketId, DepartmentId FROM TicketAssigment WHERE AssignedDate <= c.Date ORDER BY AssignedDate DESC) l
WHERE c.Date <= (SELECT MAX(AssignedDate) FROM TicketAssigment)
GROUP BY l.TicketId, c.Date
ORDER BY l.TicketId, c.Date;
Run Code Online (Sandbox Code Playgroud)
我怀疑有一种方法可以使用 LAG 和窗口框架来做到这一点,但我还没有完全弄清楚。满足要求的更有效方法是什么?
Rob*_*ley 15
使用LEAD()
得到TicketId分区中的下一行。然后加入日历表以获取之间的所有日期。
WITH TAwithnext AS
(SELECT *, LEAD(AssignmentDate) OVER (PARTITION BY TicketID ORDER BY AssignmentDate) AS NextAssignmentDate
FROM TicketAssignment
)
SELECT t.TicketID, c.Date, t.DepartmentID
FROM dbo.Calendar c
JOIN TAwithnext t
ON c.Date BETWEEN t.AssignmentDate AND ISNULL(DATEADD(day,-1,t.NextAssignmentDate),t.AssignmentDate)
;
Run Code Online (Sandbox Code Playgroud)
各种获取Calendar表的方法...
这是一种快速的方法(我尚未测试性能或可扩展性)
-- 创建日历表
-- borrowed from @Aaron's post http://sqlperformance.com/2013/01/t-sql-queries/generate-a-set-3
CREATE TABLE dbo.Calendar(d DATE PRIMARY KEY);
INSERT dbo.Calendar(d) SELECT TOP (365)
DATEADD(DAY, ROW_NUMBER() OVER (ORDER BY number)-1, '20160101')
FROM [master].dbo.spt_values
WHERE [type] = N'P' ORDER BY number;
Run Code Online (Sandbox Code Playgroud)
--- 创建您的测试表
CREATE TABLE dbo.TicketAssigment (
TicketId INT NOT NULL,
AssignedDate DATE NOT NULL,
DepartmentId INT NOT NULL);
-- truncate table dbo.TicketAssigment;
insert into dbo.TicketAssigment values (1 , '1-1-2016' , 123 )
insert into dbo.TicketAssigment values (1 , '1-4-2016' , 456 )
insert into dbo.TicketAssigment values (2 , '1-1-2016' , 25 )
insert into dbo.TicketAssigment values (2 , '1-2-2016' , 52 )
insert into dbo.TicketAssigment values (2 , '1-4-2016' , 25 )
Run Code Online (Sandbox Code Playgroud)
--- 查询以获得所需的输出
;with Cte as
(
select TicketID,
min(AssignedDate) minAD, -- This is the min date
max(AssignedDate) maxAD -- This is the max date
from TicketAssigment
group by TicketID
)
select Cte.TicketID,
c.d as AssignedDate,
( -- Get DeptID
select top(1) T.departmentID
from dbo.TicketAssigment as T
where T.TicketID = cte.TicketID and
T.AssignedDate <= c.d
order by T.AssignedDate desc
) as DepartmentID
from Cte
left outer join dbo.Calendar as c
on c.d between Cte.minAD and Cte.maxAD
order by Cte.TicketID
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
36155 次 |
最近记录: |