2016-09-23 119 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