我对LAG的功能范围有疑问。在我正在处理的具体示例中,我有一个类似于以下的表,尽管这是非常简化的:
ID Name ItemID VisitDate
----------- ---------------- ----------- ----------
316 Name,Test 9 2016-11-01
316 Name,Test 12 2016-11-01
316 Name,Test 89 2018-03-09
316 Name,Test 10 2018-03-09
316 Name,Test 1 2018-03-09
我的目标是使用LAG有一个额外的列,显示当前之前的最近的VisitDate。所以我希望看到的是
ID Name ItemID VisitDate LagDate
----------- ---------------- ----------- ---------- ----------
316 Name,Test 9 2016-11-01 NULL
316 Name,Test 12 2016-11-01 NULL
316 Name,Test 89 2018-03-09 2016-11-01
316 Name,Test 10 2018-03-09 2016-11-01
316 Name,Test 1 2018-03-09 2016-11-01
但是,我还没有办法让表格以这种方式出现。最初我写了以下代码
SELECT
TT.ID
,TT.Name
,TT.ItemID
,TT.VisitDate
,LAG(TT.VisitDate) OVER ( PARTITION BY TT.ID ORDER BY TT.VisitDate ) AS LagDate
FROM
@TestTable AS TT;
然而,这返回了下表:
ID Name ItemID VisitDate LagDate
----------- ---------------- ----------- ---------- ----------
316 Name,Test 9 2016-11-01 NULL
316 Name,Test 12 2016-11-01 2016-11-01
316 Name,Test 89 2018-03-09 2016-11-01
316 Name,Test 10 2018-03-09 2018-03-09
316 Name,Test 1 2018-03-09 2018-03-09
那时我意识到单个日期的多个ItemID值对我造成了问题。那么有没有人知道我仍然可以在这张桌子上使用LAG的方法,但是我想在每一行上找到合适的LagDate吗?
答案 0 :(得分:1)
我看不到使用窗口函数解决这个问题的简单方法。我能想到的最简单的事情就是使用OUTER APPLY
:
SELECT TT.ID, TT.Name, TT.ItemID, TT.VisitDate, X.VisitDate
FROM mytable AS TT
OUTER APPLY (
SELECT TOP 1 VisitDate
FROM mytable AS T
WHERE T.ID = TT.ID AND T.VisitDate < TT.VisitDate
ORDER BY T.VisitDate DESC) AS X
答案 1 :(得分:0)
我使用密集排名:
declare @t table (id int, _name varchar(1000),ItemID int, visitDte date)
insert into @t
values
(316, 'Name,Test', 9 ,'2016-11-01')
,(316, 'Name,Test', 12 ,'2016-11-01')
,(316, 'Name,Test' , 89 ,'2018-03-09')
,(316, 'Name,Test', 10 ,'2018-03-09')
,(316, 'Name,Test', 1 ,'2018-03-09')
;with cte as
(
select *, dr= dense_rank() over (partition by ID order by visitDte) from @t
)
, CleanUp as (
select distinct ID, visitDte, dr
from cte)
select t.*
,Cleanup.visitDte PriorVisit
from cte t
left join CleanUp on t.id=CleanUp.id and t.dr-1=Cleanup.dr
结果:
id _name ItemID visitDte dr PriorVisit
316 Name,Test 9 2016-11-01 1 NULL
316 Name,Test 12 2016-11-01 1 NULL
316 Name,Test 89 2018-03-09 2 2016-11-01
316 Name,Test 10 2018-03-09 2 2016-11-01
316 Name,Test 1 2018-03-09 2 2016-11-01
答案 2 :(得分:0)
我认为这样做会
declare @t table(ID int, Name varchar(10), ItemID int, VisitDate date);
insert into @t values
(316, 'Name,Test', 9, '2016-11-01')
, (316, 'Name,Test', 12, '2016-11-01')
, (316, 'Name,Test', 89, '2018-03-09')
, (316, 'Name,Test', 10, '2018-03-09')
, (316, 'Name,Test', 1, '2018-03-09');
select *
, (select max(VisitDate) from @t td where td.VisitDate < t.VisitDate) as dd
from @t t
order by t.VisitDate;
答案 3 :(得分:0)
LEAD / LAG功能中还有另一个参数,它是偏移量。如果不使用,则默认值为1.
LEAD ( scalar_expression [ ,offset ] , [ default ] )
OVER ( [ partition_by_clause ] order_by_clause )
在你的情况下,你需要找到“返回”行数的偏移量,你可以通过使用中间窗口计算来实现。
;WITH T (ID, Name, ItemID,VisitDate) AS
(
SELECT 316, 'Name,Test', 9, CAST('2016-11-01' AS DATE)
UNION ALL
SELECT 316, 'Name,Test', 12, CAST('2016-11-01' AS DATE)
UNION ALL
SELECT 316, 'Name,Test', 89, CAST('2018-03-09' AS DATE)
UNION ALL
SELECT 316, 'Name,Test', 10, CAST('2018-03-09' AS DATE)
UNION ALL
SELECT 316, 'Name,Test', 1, CAST('2018-03-09' AS DATE)
)
, [Intermediate] as
(
SELECT * , COUNT(Id) OVER (PARTITION BY Id , VisitDate ORDER BY Id) LagVal
FROM T
)
,[Intermediate1] as
(
SELECT * , ISNULL(LAG(LagVal) OVER (PARTITION BY Id order by Id), LagVal) LagValFixed
FROM [Intermediate]
)
SELECT * , LAG(VisitDate, LagValFixed) OVER (PARTITION BY Id ORDER BY VisitDate) PriorVisit
FROM [Intermediate1]
正如您所看到的,LagValFixed
在最后一个语句中被用作LAG
函数接受的偏移值的参数。