2016-01-08 76 views
0

我有一个名为test的表。
在测试中,我有一个ID,一个值和一个日期。
日期是为每个ID排序的。
我想选择一个ID,在更改值之前和之后的行,所以下面的示例表。SQL - 在列值更改之前和之后选择行日期

RowNum -------- ID -------值--------日期
1 ---------------- --001 --------- 1 ----------- 01/01/2015
2 ------------------ 001 --------- 1 ----------- 02/01/2015
3 ------------------ 001 - -------- 1 ----------- 04/01/2015
4 ------------------ 001 --- ------ 1 ----------- 05/01/2015
5 ------------------ 001 ----- ---- 1 ----------- 06/01/2015
6 ------------------ 001 ------- --1 ----------- 08/01/2015
7 ------------------ 001 --------- 0 ----------- 09/01/2015
8 ------------------ 001 --------- 0 ----------- 10/01/2015
9 ------------------ 001 --------- 0 ----------- 11/01/2015
10- ---------------- 001 --------- 1 ----------- 12/01/2015
11 ---- ------------- 001 --------- 1 ----------- 14/01/2015
12 ------- ----------- 002 --------- 1 ----------- 01/01/2015
13 --------- --------- 002 --------- 1 ----------- 04/01/2015
14 ----------- ------- 002 --------- 0 ----------- 05/01/2015
15 ------------- ----- 002 --------- 0 ----------- 07/01/2015

结果将返回行6,7,9,10,13,14

+0

可我知道SQL Server的版本?解决方案将有所不同 – knkarthick24

回答

4

你可以使用解析函数LAG()LEAD()在之前和之后的行访问的值,则检查它不匹配当前行中值。

SELECT * 
FROM (
    SELECT RowNum, 
     ID, 
     Value, 
     Date, 
     LAG(VALUE, 1, VALUE) OVER(ORDER BY RowNum) PrevValue, 
     LEAD(VALUE, 1, VALUE) OVER(ORDER BY RowNum) NextValue 
    FROM test) 
WHERE PrevValue <> Value 
OR NextValue <> Value 

PARAMS传递给此函数是

  1. 一些标量表达式(在这种情况下列名);
  2. 偏移量(1行之前或之后);
  3. 默认值(LAG()将返回第一行NULLLEAD()将返回NULL为最后一行,但它们似乎并不特别在你的问题,所以我用列值作为默认值)。
+0

非常感谢。 – AMorton1989

1

请参阅下面的一个,而无需使用超前滞后:

DECLARE @i  INT = 1, 
     @cnt  INT, 
     @dstvalue INT, 
     @srcvalue INT 

CREATE TABLE #result 
    ( 
    id  INT, 
    mydate DATE 
) 

CREATE TABLE #temp1 
    ( 
    rn  INT IDENTITY(1, 1), 
    id  INT, 
    mydate DATE 
) 

INSERT INTO #temp1 
      (id, 
      mydate) 
SELECT id, 
     mydate 
FROM table 
ORDER BY id, 
      mydate 

SELECT @cnt = Count(*) 
FROM #temp1 

SELECT @srcvalue = value 
FROM #temp1 
WHERE rn = @i 

WHILE (@i <= @cnt) 
    BEGIN 
     SELECT @dstvalue = value 
     FROM #temp1 
     WHERE rn = @i 

     IF(@srcvalue = @dstvalue) 
     BEGIN 
      SET @i = @i + 1 

      CONTINUE; 
     END 
     ELSE 
     BEGIN 
      SET @srcvalue = @dstvalue 

      INSERT INTO #result 
         (id, 
         mydate) 
      SELECT id, 
        mydate 
      FROM #temp 
      WHERE rn = @i - 1 
      UNION ALL 
      SELECT id, 
        mydate 
      FROM #temp 
      WHERE rn = @i 
     END 

     SET @i = @i + 1 
    END 

SELECT * 
FROM #result 
1

使用lag()lead()答案是正确的答案。如果您使用的是-SQL预Server 2012的版本,那么你基本上可以使用cross apply或相关子查询同样的事情:

select t.* 
from test t cross apply 
    (select top 1 tprev.* 
     from test tprev 
     where tprev.date < t.date 
     order by date desc 
    ) tprev cross apply 
    (select top 1 tnext.* 
     from test tnext 
     where tnext.date > t.date 
     order by date asc 
    ) tnext 
where tprev.value <> tnext.value; 
相关问题