我有下表: -
Name Status Timestamp
Ben 1 2015-01-01
Ben 1 2015-01-02
Joe 1 2015-11-12
Joe 2 2015-11-13
Joe 2 2016-12-14
Joe 2 2016-12-15
Paul 1 2015-08-16
Paul 1 2015-08-17
Paul 3 2015-08-18
Paul 3 2015-08-19
Mark 2 2015-09-20
Mark 2 2015-09-25
Mark 2 2015-09-26
Mark 3 2015-10-27
我需要一个只返回“状态”变化的行的查询。它应该在'状态'已更改,也是前一行。 例如,结果应如下所示: -
Name Status Timestamp
Joe 1 2015-11-12
Joe 2 2015-11-13
Paul 1 2015-08-17
Paul 3 2015-08-18
Mark 2 2015-09-26
Mark 3 2015-10-27
如何实现这一结果。
答案 0 :(得分:2)
您可以使用CTE
与CASE
以及LAG
和LEAD
来计算要选择的行。这适用于2012及更高版本:
创建并填充样本表(请在将来的问题中保存此步骤)
DECLARE @T as TABLE
(
Name varchar(4),
[Status] int,
[Timestamp] date
)
INSERT INTO @T VALUES
('Joe', 1, '2015-11-12'),
('Joe', 2, '2015-11-13'),
('Joe', 2, '2016-12-14'),
('Joe', 2, '2016-12-15'),
('Paul' ,1, '2015-08-16'),
('Paul' ,1, '2015-08-17'),
('Paul' ,3, '2015-08-18'),
('Paul' ,3, '2015-08-19'),
('Mark' ,2, '2015-09-20'),
('Mark' ,2, '2015-09-25'),
('Mark' ,2, '2015-09-26'),
('Mark' ,3, '2015-10-27')
cte - 请注意,我在case表达式中使用了lag和lead。
;WITH CTE AS
(
SELECT Name,
[Status],
[Timestamp],
CASE WHEN LAG([Status]) OVER(PARTITION BY Name ORDER BY [Timestamp]) <> [Status] OR
LEAD([Status]) OVER(PARTITION BY Name ORDER BY [Timestamp]) <> [Status] THEN
1
END As Filter
FROM @T
)
查询:
SELECT Name,
[Status],
[Timestamp]
FROM CTE
WHERE Filter = 1
结果:
Name Status Timestamp
Joe 1 12.11.2015 00:00:00
Joe 2 13.11.2015 00:00:00
Mark 2 26.09.2015 00:00:00
Mark 3 27.10.2015 00:00:00
Paul 1 17.08.2015 00:00:00
Paul 3 18.08.2015 00:00:00
答案 1 :(得分:0)
这可以是从2005年开始的用户:
declare @t table (Name varchar(100), S int, T date);
insert into @t values
('Joe', 1 ,'2015-11-12'),
('Joe', 2 ,'2015-11-13'),
('Joe', 2 ,'2016-12-14'),
('Joe', 2 ,'2016-12-15'),
('Paul', 1 ,'2015-08-16'),
('Paul', 1 ,'2015-08-17'),
('Paul', 3 ,'2015-08-18'),
('Paul', 3 ,'2015-08-19'),
('Mark', 2 ,'2015-09-20'),
('Mark', 2 ,'2015-09-25'),
('Mark', 2 ,'2015-09-26'),
('Mark', 3 ,'2015-10-27');
with cte as
(
select *, ROW_NUMBER() over(partition by Name order by T) as rn
from @t
)
,cte1 as
(
select c1.Name, c1.S as S1, c1.T as T1, c2.S as S2, c2.T as T2
from cte c1 join cte c2
on c1.rn + 1 = c2.rn
and c1.Name = c2.Name
where c1.S <> c2.S
)
select Name,
case n
when 1 then S1
when 2 then S2
end as Status,
case n
when 1 then T1
when 2 then T2
end as Timestamp
from cte1 cross join (select 1 n union all select 2) nums;
这是相同的,但对于从2012年开始的版本:
declare @t table (Name varchar(100), S int, T date);
insert into @t values
('Joe', 1 ,'2015-11-12'),
('Joe', 2 ,'2015-11-13'),
('Joe', 2 ,'2016-12-14'),
('Joe', 2 ,'2016-12-15'),
('Paul', 1 ,'2015-08-16'),
('Paul', 1 ,'2015-08-17'),
('Paul', 3 ,'2015-08-18'),
('Paul', 3 ,'2015-08-19'),
('Mark', 2 ,'2015-09-20'),
('Mark', 2 ,'2015-09-25'),
('Mark', 2 ,'2015-09-26'),
('Mark', 3 ,'2015-10-27');
with cte as
(
select name,
S as S1,
lead(S) over(partition by Name order by T) S2,
T as T1,
lead(T) over(partition by Name order by T) T2
from @t
)
,cte1 as
(
select *
from cte
where S1 <> S2
)
select Name,
case n
when 1 then S1
when 2 then S2
end as Status,
case n
when 1 then T1
when 2 then T2
end as Timestamp
from cte1 cross join (select 1 n union all select 2) nums;