2017-09-21 72 views
0

我有一個SQL(Teradata)問題,我一直無法解決。我知道答案可能比我看起來更簡單。SQL/Teradata:如何返回特定值及其前面的行?

我有這樣一組代碼:

ID  timestamp   location  event_type 
1111 20160601-0112  Detroit  Event A 
1111 20160602-0954  Brooklyn  Event B 
1111 20160602-1123  Brooklyn  Event A 
1112 20160912-1420  Minneapolis Event B 
1113 20161123-1742  New Orleans Event A 
1113 20161124-1841  New Orleans Event A 
1113 20161124-2100  New Orleans Event B 
1114 20170201-0959  Detroit  Event A 
1114 20170201-2350  Detroit  Event A 

這裏是條件什麼,我需要返回:

我想回到每個ID的第一個事件B,和最近的事件在事件B之前發生的事件(基於時間戳)。因此,對於上面的數據集,我會得到:

ID  timestamp   location  event_type 
1111 20160601-0112  Detroit  Event A 
1111 20160602-0954  Brooklyn  Event B 
1113 20161124-1841  New Orleans Event A 
1113 20161124-2100  New Orleans Event B 

爲1111第三個記錄沒有得到恢復,因爲它發生後,事件B. ID 1112沒有得到恢復,因爲它不具有事件A在它之前。 1113的第一條記錄不會被返回,因爲在它之後有更接近的事件A(到事件B)。 1114沒有得到返回,因爲沒有事件B.

我一直在這個工作了幾個小時到了我不再接近它的地步......任何幫助將不勝感激!

+0

每個ID可能有*多個*'B',然後您只需要第一個? – dnoeth

+0

是的,理論上是這樣,但我可以查詢數據並創建一個只有第一個事件B記錄(和所有事件A記錄)的臨時表,如果它更容易。 – slim88

+0

爲什麼ID 1112不在列表中?是因爲它缺少事件A嗎? – JNevill

回答

0

這與MS SQL 2012的工作 - 不知道如果語法是相同的?

;WITH myData AS 
    (
     SELECT 
      ID, 
      min(timestamp) as timestamp, 
      location, 
      event_type 
     FROM 
      tableName 
     GROUP BY 
      ID, 
      location, 
      event_type 
    ) 
     SELECT 
      * 
     FROM 
      myData 
     WHERE 
      (
       myData.timestamp < (SELECT top 1 m2.timestamp FROM myData m2 WHERE m2.ID = myData.ID AND m2.event_type = 'Event B' ORDER BY m2.timestamp ASC) 
       OR 
       myData.event_type = 'Event B' 
      ) 
      AND (SELECT Count(*) FROM myData m2 WHERE m2.ID = myData.ID AND m2.event_type = 'Event A') > 0 
     ORDER BY 
      myData.timestamp 
+0

欣賞迴應! - 非常接近工作,但是在Teradata的子查詢中不支持'TOP N' - 在子查詢中有什麼限制是我一直面臨的問題。 – slim88

+0

您可以用ORDER BY之後的「LIMIT 1」替換「TOP N」嗎? – West

+0

不幸的是,Teradata的子查詢中也不允許使用ORDER BY。 – slim88

2

鑑於您的示例數據,我認爲以下幾點應該可以做到。

SELECT * 
FROM testtable 
QUALIFY 

    (
     event_type = 'Event A' 
     AND 
     min(event_type) OVER (PARTITION BY id ORDER BY "timestamp" ROWS BETWEEN 1 FOLLOWING AND 1 FOLLOWING) = 'Event B' 
    ) OR 
    (
     event_type = 'Event B' 
     AND 
     max(event_type) OVER (PARTITION BY id ORDER BY "timestamp" ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) = 'Event A' 
    ) 

這裏我們使用Window函數來測試結果集中記錄之前和之後的記錄。我們在QUALIFY子句中這樣做,就像WHERE子句一樣,但是對於窗口函數。

打破這個資格聲明:

 event_type = 'Event A' 
     AND 
     min(event_type) OVER (PARTITION BY id ORDER BY "timestamp" ROWS BETWEEN 1 FOLLOWING AND 1 FOLLOWING) = 'Event B' 

是說:「如果這個當前記錄是‘事件A’,當按時間戳此ID下令第二天記錄‘事件B’則允許記錄」。

 event_type = 'Event B' 
     AND 
     max(event_type) OVER (PARTITION BY id ORDER BY "timestamp" ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) = 'Event A' 

是說:「如果這個當前記錄‘事件B’,當按時間戳此ID訂購了此前的紀錄是‘事件A’則允許記錄。

可能需要得到在更多的創造QUALIFY條款搭上邊的情況,但一旦你換你的頭周圍一切是如何運作的,你可以在那裏得到相當的創意


例:

CREATE MULTISET VOLATILE TABLE testtable 
(
id int, 
ts varchar(20), 
location varchar(20), 
event_type varchar(20) 

) PRIMARY INDEX (id) ON COMMIT PRESERVE ROWS; 

INSERT INTO testtable VALUES (1111,'20160601-0112','Detroit','Event A'); 
INSERT INTO testtable VALUES (1111,'20160602-0954','Brooklyn','Event B'); 
INSERT INTO testtable VALUES (1111,'20160602-1123','Brooklyn','Event A'); 
INSERT INTO testtable VALUES (1112,'20160912-1420','Minneapolis','Event B'); 
INSERT INTO testtable VALUES (1113,'20161123-1742','New Orleans','Event A'); 
INSERT INTO testtable VALUES (1113,'20161124-1841','New Orleans','Event A'); 
INSERT INTO testtable VALUES (1113,'20161124-2100','New Orleans','Event B'); 
INSERT INTO testtable VALUES (1114,'20170201-0959','Detroit','Event A'); 
INSERT INTO testtable VALUES (1114,'20170201-2350','Detroit','Event A'); 


SELECT * 
FROM testtable 
QUALIFY 

    (
     event_type = 'Event A' 
     AND 
     min(event_type) OVER (PARTITION BY id ORDER BY ts ROWS BETWEEN 1 FOLLOWING AND 1 FOLLOWING) = 'Event B' 
    ) OR 
    (
     event_type = 'Event B' 
     AND 
     max(event_type) OVER (PARTITION BY id ORDER BY ts ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) = 'Event A' 
    ); 

+------+---------------+-------------+------------+ 
| id |  ts  | location | event_type | 
+------+---------------+-------------+------------+ 
| 1111 | 20160601-0112 | Detroit  | Event A | 
| 1111 | 20160602-0954 | Brooklyn | Event B | 
| 1113 | 20161124-1841 | New Orleans | Event A | 
| 1113 | 20161124-2100 | New Orleans | Event B | 
+------+---------------+-------------+------------+ 
+2

如果每個ID有多個「B」,則這將全部轉發,以獲得第一個只有您可以添加的AND和ORDER BY ts(當事件類型='事件B'時1結束) ORDER BY ts ROWS BETWEEN無界先導AND 1以下)= 1'。這將'1'分配給第一個'B'和前一行。 – dnoeth

+0

謝謝!這對我的確切數據集沒有太大的幫助,但是使用你的回答(JNevill和dnoeth)並做了一些細微的修改,我能夠得到我的結果! – slim88