2016-01-08 124 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; 
相關問題