我正在编写TSQL查询。
我有下表,其中A列和B列偶尔会改变。 我对A或B与前一行相比发生变化的每一行感兴趣(或者当previos行不存在时,也就是说,第一行)。每个日期都将是唯一的。
Date A B SysId
2015-02-01 00:00:00.000 2 1201 949410
2015-01-01 00:00:00.000 3 1201 949410
2014-01-01 00:00:00.000 2 1201 949410
2013-01-01 00:00:00.000 2 1200 949410
2012-01-01 00:00:00.000 2 1200 949410
2011-01-01 00:00:00.000 2 1200 949410
2010-01-01 00:00:00.000 2 1200 949410
2009-01-01 00:00:00.000 2 1200 949410
2008-01-01 00:00:00.000 2 1200 949410
2007-01-01 00:00:00.000 2 1200 949410
2006-01-01 00:00:00.000 2 1200 949410
2005-01-01 00:00:00.000 2 1200 949410
2004-01-01 00:00:00.000 2 1200 949410
2003-01-01 00:00:00.000 2 1200 949410
2002-01-01 00:00:00.000 3 1200 949410
2001-01-01 00:00:00.000 2 1200 949410
2000-01-01 00:00:00.000 3 1200 949410
1999-01-01 00:00:00.000 3 1200 949410
1998-01-01 00:00:00.000 3 1200 949410
1997-01-01 00:00:00.000 3 1200 949410
1996-01-01 00:00:00.000 3 1200 949410
1995-01-01 00:00:00.000 3 1200 949410
1994-01-01 00:00:00.000 3 1200 949410
1993-01-01 00:00:00.000 3 1200 949410
1992-01-01 00:00:00.000 3 1200 949410
1991-01-01 00:00:00.000 3 1200 949410
1990-01-01 00:00:00.000 3 1200 949410
1989-01-01 00:00:00.000 3 1200 949410
1988-01-01 00:00:00.000 3 1200 949410
1987-01-01 00:00:00.000 3 1200 949410
1986-01-01 00:00:00.000 3 1200 949410
1985-01-01 00:00:00.000 3 1200 949410
1984-01-01 00:00:00.000 2 1200 949410
在这种情况下,结果应为:
Date A B SysId
2015-02-01 00:00:00.000 2 1201 949410
2015-01-01 00:00:00.000 3 1201 949410
2014-01-01 00:00:00.000 2 1201 949410
2003-01-01 00:00:00.000 2 1200 949410
2002-01-01 00:00:00.000 3 1200 949410
2001-01-01 00:00:00.000 2 1200 949410
1985-01-01 00:00:00.000 3 1200 949410
1984-01-01 00:00:00.000 2 1200 949410
因为我们对A或B已经改变的第一行感兴趣。
我有一个非常丑陋和昂贵的选择,它为我做这个:
SELECT Date, A, B, SysId
FROM SysHistory fb1
WHERE fb1.SysId = 949410
AND
(
(
((
SELECT TOP 1 fb2b.A
FROM SysHistory fb2b
WHERE fb2b.Date < fb1.Date
AND fb2b.SysId = 949410
order by Date DESC
)) <> fb1.StatusId
OR
((
SELECT TOP 1 fb2a.A
FROM SysHistory fb2a
WHERE fb2a.Date < fb1.Date
AND fb2a.SysId= 949410
order by Date DESC
)) IS NULL
)
OR
(
((
SELECT TOP 1 fb3b.B
FROM SysHistory fb3b
WHERE fb3b.Date < fb3b.Date
AND fb3b.SysId= 949410
order by Date DESC
)) <> fb1.StatusId
OR
((
SELECT TOP 1 fb3a.B
FROM SysHistory fb3a
WHERE fb3a.Date < fb1.Date
AND fb3a.SysId = 949410
order by Date DESC
)) IS NULL
)
)
order by Date DESC
请注意,每次我从前一行获取顶部A或B属性。由于前一行可能为null(在我们位于表的第一行的情况下),我还有一个用于检查null的A和B的OR语句。
我觉得必须有更好的方法来做到这一点。
在TSQL中,是否可以比较同一子选择中的多个列?或者只是一般情况下,您如何改进此查询?无论如何都要使它更紧凑或更快?
我想我的问题接近于最佳实践,但我觉得这在技术上是一个语法问题。
导入更新 我现在注意到我的查询实际上并没有给我想要的结果。所以上面的SQL查询似乎不起作用。这种情况下的结果应该是
Date A B SysId
2015-02-01 00:00:00.000 2 1201 949410
2015-01-01 00:00:00.000 3 1201 949410
2014-01-01 00:00:00.000 2 1201 949410
2003-01-01 00:00:00.000 2 1200 949410
2002-01-01 00:00:00.000 3 1200 949410
2001-01-01 00:00:00.000 2 1200 949410
1985-01-01 00:00:00.000 3 1200 949410
1984-01-01 00:00:00.000 2 1200 949410
相反,结果是:
Date A B SysId
2015-02-01 00:00:00.000 2 1201 949410
2015-01-01 00:00:00.000 3 1201 949410
2003-01-01 00:00:00.000 2 1200 949410
2002-01-01 00:00:00.000 3 1200 949410
2001-01-01 00:00:00.000 2 1200 949410
1985-01-01 00:00:00.000 3 1200 949410
1984-01-01 00:00:00.000 2 1200 949410
答案 0 :(得分:2)
您可以对数据应用ROW_NUMBER()
,以便您可以执行自联接以查找以前的行:
;WITH Numbered as (
SELECT Date, A, B, SysId,
ROW_NUMBER() OVER (ORDER BY Date desc) as rn
FROM SysHistory fb1
WHERE fb1.SysId = 949410
)
select n1.*
from Numbered n1
left join
Numbered n2
on n1.rn = n2.rn - 1
where
n2.Date is null or --If you want to include the earliest row
n1.A <> n2.A or
n1.B <> n2.B
结果(将您的示例数据放在名为@SysHistory
的表变量中,在上面的查询中更改为引用它,并将Date
列转义为[Date]
,因为使用类型名称作为列名称通常是一个坏主意):
Date A B SysId rn
----------------------- ----------- ----------- ----------- --------------------
2015-02-01 00:00:00.000 2 1201 949410 1
2015-01-01 00:00:00.000 3 1201 949410 2
2014-01-01 00:00:00.000 2 1201 949410 3
2003-01-01 00:00:00.000 2 1200 949410 14
2002-01-01 00:00:00.000 3 1200 949410 15
2001-01-01 00:00:00.000 2 1200 949410 16
1985-01-01 00:00:00.000 3 1200 949410 32
1984-01-01 00:00:00.000 2 1200 949410 33
这似乎符合您的预期结果(除了我的额外列)