SQL Server 2005 - 在1个字段

时间:2018-02-21 21:03:07

标签: sql-server-2005

我有一个包含2个字段的源表,一个日期和一个状态代码。我需要一个查询来删除重复的连续状态代码,只保留具有不同状态的第一个日期的行。例如:

Date       Status 
10/02/2004   A
10/12/2004   B
10/14/2004   B
11/22/2004   C
11/23/2004   C
12/03/2004   C
03/05/2006   B

所需的结果集将是:

10/02/2004   A
10/12/2004   B
11/22/2004   C
03/05/2006   B

主要问题是所有分组功能(GROUP BY和ROW_NUMBER()OVER)似乎并不关心顺序,因此在示例中,所有" B"状态记录将被分组在一起,这是不正确的,因为状态从非 - " B"到" B"两个不同的时间。

使用基于游标的循环来生成结果很容易解决这个问题。只需记住变量中的当前值,并在循环时测试每个记录。这非常有效,但速度非常慢(实际数据超过20分钟)。

这需要在SQL Server 2005及更高版本上运行,因此一些较新的窗口函数不可用。有没有办法使用基于集合的查询来执行此操作,这可能会更快地运行?这似乎应该是一件简单的事情,但也许不是。关于SO的其他类似问题似乎依赖于我们没有的其他ID或序列字段。

1 个答案:

答案 0 :(得分:0)

常规分组在这种情况下没有帮助的原因是因为分组标准需要引用2个不同记录中的字段以确定是否应该发生分组中断。由于SQL 2005落后于较新版本,因此我们没有滞后函数来查看先前记录的值。相反,我们需要进行自联接才能访问先前的记录。为此,我们需要使用ROW_NUMBER()在CTE中创建临时序列字段。然后在自联接中使用该生成的序列来查看先前的记录。我们最终得到了类似的东西:

;WITH tmp AS (
  SELECT myDate,myStatus,ROW_NUMBER() OVER (ORDER BY myDate) as seq
  FROM myTable )
SELECT tmp.* FROM tmp LEFT JOIN tmp t2 ON t2.seq = tmp.seq-1
WHERE t2.seq is null OR t2.myStatus!=tmp.myStatus

因此,即使原始数据没有序列列,我们也可以动态生成它,以便能够使用自联接找到任何给定其他记录的先前记录(如果有)。然后我们得到所需的结果,只选择状态从先前记录改变的记录。