如何仅获取下一行(按日期戳)在某些字段中具有不同属性的行?

时间:2014-03-20 22:02:10

标签: sql sql-server sql-server-2008

我有一个这样的数据表:

+--------------+-------------------------+----------+
|  o_objguid   |        o_acttime        | o_action |
+--------------+-------------------------+----------+
| 478n8937g990 | 2013-10-02 10:45:33.423 |     1012 |
| 478n8937g990 | 2013-10-02 11:21:57.207 |     1012 |
| 478n8937g990 | 2013-10-02 11:21:57.887 |     1012 |
| 478n8937g990 | 2013-11-15 13:42:11.983 |     1013 |
+--------------+-------------------------+----------+

我希望查询只返回那些行,对于给定的o_objguid,时间序列中的下一行没有{10}的o_action

我使用以下查询:

select d1.* from dbo.dms_audt d1
inner join
(select d2.o_objguid,d2.o_acttime,d2.o_action,
min(datediff(second,d1.o_acttime,d2.o_acttime)) as intervalToNext
from dbo.dms_audt d1
inner join
dbo.dms_audt d2
on
d1.o_objguid=d2.o_objguid
where
d2.o_acttime>d1.o_acttime
group by 
d2.o_objguid,d2.o_acttime,d2.o_action) d2
on
d1.o_objguid=d2.o_objguid
where
datediff(second,d1.o_acttime,d2.o_acttime)=intervalToNext
and
d1.o_action=1012
and
d2.o_action<>1012

此查询不会返回2013-10-02 10:45:33.423的o_acttime行,因为下一行具有相同的o_action。但是因为我在second函数中使用了datediff()的参数,所以这些行o_acttime

2013-10-02 11:21:57.207
2013-10-02 11:21:57.887
为了计算的目的,

被视为相同的日期值,因此返回两行,而实际上唯一应返回的行是2013-10-02 11:21:57.887行。

我尝试将datediff()参数更改为millisecond,但这会导致溢出错误,可能是因为几天或更长时间的日期差异将有太多毫秒才能适合返回类型。

我想我可以将查询的结果加入到另一个使用max(o_acttime)的查询中,这样只有一组具有相同o_acttime的结果中的最高intervalToNext将被退回。但是我担心这个查询的大小和性能;这里有很多嵌套的笛卡尔积,并且对于一组100万行来说它已经很慢了。有没有更好的方法来获得我想要的结果?

2 个答案:

答案 0 :(得分:2)

可悲的是,SQL Server 2008没有LEAD()(2012年的功能),这会使查询变得微不足道,但您可以使用ROW_NUMBER()模拟它;

WITH cte AS (
  SELECT *, ROW_NUMBER() OVER (ORDER BY o_acttime) rn
  FROM table1
  WHERE o_objguid = '478n8937g990'
)
SELECT a.*
FROM cte a
JOIN cte b
  ON a.rn = b.rn - 1 AND b.o_action <> 1012;

An SQLfiddle to test with

答案 1 :(得分:2)

这应该可以在不计算两次CTE的情况下工作。根据数据和索引策略,它可能会或可能不会比Joachim的响应更快。

SELECT
    *
FROM dbo.dms_audt d1
CROSS APPLY ( -- get next action
    SELECT TOP 1
        *
    FROM dbo.tbl_audt X
    WHERE   d1.o_objguid = X.o_objguid
        AND d1.o_acttime < X.o_acttime
    ORDER BY X.o_acttime
) D2
WHERE   D1.o_action = 1012
    AND D2.o_action != 1012