2017-03-27 46 views
1

我想識別其值從正值過渡到零或負值的ID。如何識別值從正值變爲負值或負值的ID?

所以,如果我們有一個表如下:


ID VALUES ORDER 
1 20  2 
1 10  1 
2 0  2 
2 100 1 
3 -10 2 
3 5  1 
4 0  2 
4 0  1 
5 -3  2 
5 25  1 
6 30  2 
6 -50  1 
7 -10  2 
7 0  1 
8 -100 3 
8 50  2 
8 100  1 
9 -10  4 
9 0  3 
9 10  2 
9 20  1 

結果應該如下,其中從100過渡到0 ID 2的值,從5轉換到-10 ID 3的值,ID 5的值從25過渡到-3。我們對ID 6不感興趣,因爲它的值從負值轉變爲正值 - 我們只關心ID值從正值變爲0或負值(而不是反之亦然)的ID。我們也可以有從0到負數但不爲0到0的ID:


ID VALUES ORDER 
2 0  2 
2 100  1 
3 -10  2 
3 5  1 
5 -3  2 
5 25  1 
7 -10  2 
7 0  1 
8 -100  3 
8 50  2 
9 -10  4 
9 0  3 
9 10  2 

我將如何實現這樣的結果?

+1

你怎麼知道過渡發生的順序 - 是否有另一列告訴你每個ID的兩個值的發生順序?每個ID總是有兩個值? –

+0

謝謝亞歷克斯。我已經爲每個ID包含一個訂單列表 - 因此每個ID的訂單#1首先出現在ID後面跟着訂單#2,如果有訂單#3,則表示第三個條目。每個ID也可以有兩個以上的值 - 這只是爲了說明這個概念。 –

+0

好的,如果ID變爲+3,-3,+ 3會怎樣?這是雙向過渡。或相反亦然。您是否以某種方式查看ID的所有值或順序對? –

回答

1

你可以使用分析滯後/超前功能,每個ID找到一個和下一個值:

select id, value, seq, 
    lag(value) over (partition by id order by seq) as prev_val, 
    lead(value) over (partition by id order by seq) as next_val 
from your_table 
order by id, seq desc; 

     ID  VALUE  SEQ PREV_VAL NEXT_VAL 
---------- ---------- ---------- ---------- ---------- 
     1   20   2   10   
     1   10   1     20 
     2   0   2  100   
     2  100   1      0 
     3  -10   2   5   
     3   5   1     -10 
     4   0   2   0   
     4   0   1      0 
     5   -3   2   25   
     5   25   1     -3 
     6   30   2  -50   
     6  -50   1     30 
     7  -10   2   0   
     7   0   1     -10 
     8  -100   3   50   
     8   50   2  100  -100 
     8  100   1     50 
     9  -10   3   0   
     9   0   2   10  -10 
     9   20   1     10 
     9   10   1   20   0 

(我改變了列名,如順序和值保留)。然後,您可以使用它作爲一個子查詢和過濾器,你希望看到的組合:

select id, value, seq 
from (
    select id, value, seq, 
    lag(value) over (partition by id order by seq) as prev_val, 
    lead(value) over (partition by id order by seq) as next_val 
    from your_table 
) 
where (prev_val >=0 and value <= 0 and not (prev_val = 0 and value = 0)) 
or (value >= 0 and next_val <= 0 and not (value = 0 and next_val = 0)) 
order by id, seq desc; 

     ID  VALUE  SEQ 
---------- ---------- ---------- 
     2   0   2 
     2  100   1 
     3  -10   2 
     3   5   1 
     5   -3   2 
     5   25   1 
     7  -10   2 
     7   0   1 
     8  -100   3 
     8   50   2 
     9  -10   3 
     9   0   2 
     9   10   1 

戈登提到的,如果你只想要的ID - 沒有參與的價值 - 你只需要超前或滯後值,而不是都。

+0

謝謝Alex!這工作得很好! –

1

我認爲你可以做到這一點使用lead()

select distinct id 
from (select t.*, 
      lead(value) over (partition by id order by seq) as next_val, 
     from t 
    ) t 
where value > 0 and next_val <= 0; 

注意我用了亞歷克斯的命名約定。

+0

取決於OP是否只需要ID,或者還需要問題中所示的值。這也沒有抓住從零到負的ID 7。 (並且有一個多餘的逗號* 8-) –

+0

這可能是12c中的MATCH_RECOGNIZE的用例 – BobC

+0

謝謝Gordon!非常感謝幫助。 –

1

這應該給你相同的結果,但在行

select t1.ID, t1.VALUES, t2.VALUES from TABLE t1 
join TABLE t2 on t1.VALUE < t2.VALUE and t1.ID = t2.ID and t1.ORDER > t2.ORDER 
where t1.ORDER = t2.ORDER +1 and not (t1.VALUE >0 and t2.VALUE >0) 

表是這樣的,如果這對你來說是有用的:

ID Value1 Value2 
2  0   100 
3  -10  5 
5  -3  25 
7  -10  0 
8  -100  50 
9  -10  0 
9  0   10 
+0

我不認爲它應該包括第二個ID行(50,100)或第三個ID 9行(10,20)? –

+0

行,更正,現在可以 – Mocas

+0

謝謝@ user2410199。非常感謝幫助。 –

0

如果您正在使用Oracle 12c中,這是一個用於MATCH_RECOGNIZE的很好用例。在這種情況下,它會做像這樣:

SELECT id, value, ord FROM d 
MATCH_RECOGNIZE (partition by id 
        order by ord 
        all rows per match 
        after match skip past last row 
        pattern (posorzero neg | pos negorzero) 
        define 
        neg as neg.value < 0, 
        negorzero as negorzero.value <= 0, 
        pos as pos.value > 0, 
        posorzero as posorzero.value>= 0 
        ) 
order by id, ord desc; 

ID VALUE ORD 
-- ----- --- 
2  0  2 
2  100  1 
3  -10  2 
3  5  1 
5  -3  2 
5  25  1 
7  -10  2 
7  0  1 
8 -100  3 
8  50  2 
9  0  3 
9  10  2 

唯一的一點是,這並沒有所需輸出包括以下行:

9 -10  4 

在其他情況下,你想要的輸出似乎是「只包括每個id有助於交叉的行」。通過本身代表着一個交叉爲你定義它

9 0  3 
9 10  2 

...:您已經包含在您需要的輸出這一行將不符合這一定義,因爲這些行。

如果您對請求的輸出應包含的內容有一致且更好的定義,請讓我知道,我會更新我的答案。