仅选择已更改的行

时间:2013-07-03 13:44:01

标签: sql sql-server postgresql

我的行看起来像这样:

1
0 ----> Change! This row is of interest
1 ----> Change again.
1
1
1
1
1
0 ----> Change.
1 ----> Change.

在新的1之前可能有一百万个零,我只想要更改(标记为Change的行)。这将给我带来约1000万行的结果。我们支持SQLServer和PostGresSQL。它按时间戳列排序。 0表示系统脱机标志,1表示系统处于联机状态。服务会定期报告此信息并为其添加时间戳。

有什么想法吗? 编辑: 还有很多其他列,一个是确定订单的时间戳列。 0表示系统脱机标志,1表示系统处于联机状态。服务会定期报告此信息并为其添加时间戳。

干杯

4 个答案:

答案 0 :(得分:3)

行。所以根据评论,我们知道有时间戳列。我们假设这被命名为" event_when",并且0/1列被命名为" status"。

所以,我们可以:

with x as (
    select
        *,
        lag(status) over (order by event_when) is distinct from status as interesting
    from table
)
select * from x where interesting;

答案 1 :(得分:2)

如果您有ID,并且它们是连续的,您可以尝试类似:

SELECT table1.* FROM table table1, table table2 
WHERE table1.id = table2.id- 1
AND table1.value != table2.value

如果没有看到结构的其余部分,说起来有点难,但在上述情况下,value是包含01id的列是主键。如果您没有id列,或者它们不是增量列,那么您可能需要指定更复杂的选择器,或者在此处包含更多的架构。

答案 2 :(得分:0)

我们必须知道如何找到前一行,但一般解决方案是(我假设你的行有列Date并且它是唯一的)

select *
from temp as t1
    outer apply
    (
        select top 1 *
        from temp as t2
        where t2.Date < t1.Date /* or you columns */
        order by t2.Date desc /* or you columns */
    )
where t2.value <> t1.value

编辑:由于我通常在2008 R2 SQL Server上工作,所以我忘记了LAG和LEAD功能。所以,基于@depesz对PostgreSQL的回答,这里是SQL Server版本:

with CTE_temp as (
    select
        *,
        lag([State]) over (order by [Time]) as State_Previous
    from temp
)
select *
from CTE_temp
where State_Previous <> [State]

SQL FIDDLE EXAMPLE

答案 3 :(得分:-1)

选项#1 :使用MS SQL SERVER 2008

使用时间戳排序,我们可以使用rank()函数和临时表。也可以使用CTE和表变量。性能是一个棘手的部分,所以我建议测试这三个选项,如果这将在未来重复。我将展示两个例子:

  • TEMPORARY TABLE(try it in SQLFiddle):

    select  rank() OVER (ORDER BY order_timestamp) as 'Rank', status into temp1 from temp
    
    select t1.status as status, case when t1.status - t2.status = 0 then 'not changed' else 'changed' end as changed
    from temp1 t1, temp1 t2 
    where t1.Rank = t2.Rank + 1
    
    drop table temp1 
    
  • CTE(try it in SQLFiddle):

    with CTE_temp as (
        select rank() OVER (ORDER BY order_timestamp) as 'Rank', * 
        from temp
    )
    select t1.status as status, case when t1.status - t2.status = 0 then 'not changed' else 'changed' end as changed
    from CTE_temp t1, CTE_temp t2 
    where t1.Rank = t2.Rank + 1
    

选项#2 :使用MS SQL SERVER 2012

MS SQL SERVER 2012介绍了leadlaghttp://blog.sqlauthority.com/2011/11/15/sql-server-introduction-to-lead-and-lag-analytic-functions-introduced-in-sql-server-2012/)。

在这种情况下,选项#1仍然有效,但您也可以尝试@ RomanPekar的解决方案。

<强>更新

基于@ RomanPekar的评论(以及某人的评论),我不得不说临时表可以比CTE和表变量完美地执行,特别是当一大组数据是预期。优化程序可以使用临时表中的统计信息来建立其查询计划,这可以提高性能。

同样,根据OP想要在之后提供数据的使用(可能更多查询),临时表仍然存在,不必执行新查询,并且索引可用于提高这些情况下的性能。

BTW,攻击我的答案并将其转换为CTE或表格变量很容易,所以我建议OP测试这三种情况的性能,如果这是他将来会重复的操作。