2016-09-23 58 views
0

我有這個表:SQL:基於時間戳和代碼查詢狀態

Timestamp[DateTime] | Code [Text] 
01-jan-2010 00:00:00 | ABC   
01-jan-2010 02:00:00 | AAA   
01-jan-2010 02:20:00 |    
01-jan-2010 03:00:00 | BBB   

我想GROUP BY開始和結束時間的條目,根據該信息Code != ''意味着RUNNING和一切其他的意思是STOPPED。 結果是這樣的(不重複RUNNING項,直至STOPPED找到)

Timestamp[DateTime] | Status [Text] 
01-jan-2010 00:00:00 | RUNNING  
01-jan-2010 02:20:00 | STOPPED  
01-jan-2010 03:00:00 | RUNNING  

我想在一個單一的查詢選擇這兩種類型,但我不認爲這是完全正確的列名是相同的在這兩個子查詢上,它不會將RUNNING條目分組。什麼是實現這一結果的最佳方法?我相信目前的做法對我不會有很大的幫助,所以任何想法都是值得歡迎的。

標準的SQL語法是最好的。 SQL Server Express也是一個選項。

當前的嘗試:

SELECT Timestamp, Status 
FROM (SELECT Timestamp, 'RUNNING' as Status FROM MyTable WHERE Code != ''), 
    (SELECT Timestamp, 'STOPPED' as Status FROM MyTable WHERE Code = '') 
+1

你能證明你目前的做法,也標記DBMS的參與? –

+0

@vkp當然,我想使用子查詢,如下所示:SELECT Timestamp,Status FROM(SELECT Timestamp,'RUNNING'as Status FROM MyTable WHERE Code =''),(SELECT Timestamp,'STOPPED'as Status FROM MyTable WHERE Code!='')。至於DBMS,我使用的是專有的,我也可以使用SQL Server Express,這就是爲什麼我更喜歡使用標準的SQL語法,以便能夠在多個數據庫中進行測試。 –

+1

嗯你的解釋停止和運行似乎倒退,如果代碼!=''意味着停止,那麼唯一的運行記錄將是2:20 ..... – Matt

回答

1
SELECT 
    r.Timestamp 
    ,CASE WHEN r.T1Code != '' THEN 'RUNNING' ELSE 'STOPPED' END as Status 
FROM 
    (
     SELECT 
      t1.Timestamp 
      ,CAST(COALESCE(t1.Code,'') AS VARCHAR(MAX)) as T1Code 
      ,(SELECT TOP 1 CAST(COALESCE(t2.Code,'') AS VARCHAR(MAX)) 
      FROM 
       myTable t2 
      WHERE 
       t2.Timestamp < t1.Timestamp 
      ORDER BY 
       t2.Timestamp DESC) as T2Code 
     FROM 
      myTable t1 
    ) r 
WHERE 
    NOT(r.T1Code != '' AND r.T2Code != '') 
    OR r.T2Code IS NULL 

更新,以便測試null或空字符串,並考慮到文本數據類型的比較考慮的問題。

http://rextester.com/OBWS90094顯示它的工作原理

如果你真的想停止/運行的反向意義時,代碼不爲空或空,然後更改以下行:

CASE WHEN r.T1Code = '' THEN 'RUNNING' ELSE 'STOPPED' END as Status 

WHERE 
    NOT(r.T1Code = '' AND r.T2Code = '') 
    OR r.T2Code IS NULL 

這表明它的工作原理:http://rextester.com/KUGW22706

實際上,您可以在一個查詢中完成所有操作,但在嵌套查詢中顯示邏輯稍微簡單一點,以便我可以使用列引用。如果您的DBMS支持橫向連接/應用和/或LAG/LEAD窗口功能,它會更簡單一些,但您可以在您的Column定義中使用相關子查詢來做同樣的事情。該子查詢獲取前一個時間戳記行的代碼。如果當前行代碼和上一行代碼!=''那麼它仍在運行,所以不顯示記錄。但是如果t2.Code爲空,你仍然需要包含第一條記錄。

+0

你實際上不需要橫向連接(「apply」) –

+0

@a_horse_with_no_name我知道我沒有使用一個,我只是說,因爲他沒有外部申請或交叉申請,他可以使用相關的子查詢。這有點像說這會更容易,如果....我將編輯以消除混淆 – Matt

+0

同樣的事情發生的兩個例子,它只是返回「停止」,當我尋找空值,我猜Code' t DBNULL有沒有辦法驗證它?它也不允許我在文本列中使用!=運算符。我正在使用SQL Express進行測試。 –

2

這是一個間隙和島嶼問題與捻度:

select "timestamp", 
     case 
     when code is null then 'running' 
     else 'stopped' 
     end as status 
from (
    select "timestamp", code, 
      lag(code) over (order by timestamp) as prev_code 
    from mytable 
) as t 
where prev_code is null or code is null 

以上是標準ANSI SQL。

請注意,我必須將timestamp放在引號中,因爲它是標準SQL中的保留字。我也在檢查null而不是code列中的空字符串。

這是給你的樣本數據運行的例子:

http://rextester.com/WWEYP16675

+0

它只返回「停止」,我相信這些值不是真的那麼,我該如何驗證它?我在遷移數據後使用SQL Server Express進行測試。 –

+0

@ D.Can:然後檢查一個空字符串'='''而不是'null' –

1
select [Timestamp],[status] 
from 
(
select [Timestamp] 
, lag(Code,1,'') over (order by [Timestamp]) lead 
,code 
,iif(Code ='','STOPPED','RUNNING') [status] 
from [Table]) x 
where lead = '' or code ='' 
1

嘗試用下面的代碼。

;WITH cte_1 
AS 
(SELECT [TimeStamp], code, 
      lag(code) over (order by [TimeStamp]) as LCode 
    FROM YourTable) 
SELECT [TimeStamp],CASE WHEN ISNULL(LCode,'')='' THEN 'RUNNING' ELSE 'STOPPED' END Status 
FROM cte_1 
WHERE ISNULL(code,'')='' or ISNULL(LCode,'')='' 

輸出:

enter image description here