SQL:基于时间戳和代码查询状态

时间:2016-09-23 19:05:45

标签: sql sql-server

我有这张桌子:

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           

我希望根据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 = '')

4 个答案:

答案 0 :(得分: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

答案 1 :(得分: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或Empty字符串,并考虑文本数据类型的比较问题。

http://rextester.com/OBWS90094显示效果

如果您真的想要在Code不为null或为空时停止/运行的相反含义,请更改以下行:

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

AND

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

这表明它有效:http://rextester.com/KUGW22706

您实际上可以在一个查询中完成所有操作,但在嵌套查询中显示逻辑会更容易,以便我可以使用列引用。如果您的DBMS支持诸如横向连接/应用和/或LAG / LEAD窗口函数之类的东西,那么它会更简单一些,但您可以使用Column定义中的相关子查询来执行相同的操作。该子查询获取前一个Timestamp Row的代码。如果当前行代码和前一行代码都是!=&#39;&#39;然后它仍在运行,所以不要显示记录。但是你仍然需要包含第一条记录,所以测试t2.Code是否为空。

答案 2 :(得分: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 =''

答案 3 :(得分: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