查询以有条件地计算与先前记录的数据

时间:2011-12-21 22:04:00

标签: mysql

如果标题不够具有描述性,请原谅 这是我的问题场景:

我有一个包含以下列(组成)的表:

oid rev state time
1     0   S   T1
2     0   S   T2
1     0   A   T3
2     0   A   T4
2     1   MS  T5
2     1   MA  T6
2     1   M   T7
2     2   MS  T8
2     2   M   T9

时间列是varchar(包含日期/时间)
我需要找到每个订单从状态转换到状态所需的时间 - 有效状态转换定义为:

S->A  
MS->MA  
MS-M

(即,转换可以是从提交到确认,修改提交到修改确认或修改提交到修改) MS可以转换为MA,然后转换为M,但我只对从MS到MA的过渡感兴趣。

在上面:

oid 1 transitioned from S to A.  
oid 2 changed from S to A (rev 0)
oid 2 changed from MS to MA (rev 1) - here we don't want to consider transition to M
oid 2 changed from MS to M (rev 2)

因此查询输出应如下所示(timeTaken将以毫秒为单位):

oid rev timeTaken state
1    0   (T3-T1)    A
2    0   (T4-T2)    A
2    1   (T6-T5)    MA
2    2   (T9-T8)    M

因此,如果当前记录状态是MA或M,则仅当前一记录状态为MS时才需要计算时间差(假设这是按照oid,rev,time排序)。如果当前记录状态为M,则跳过前一记录状态为MA。

无论如何使用mysql中的sql查询来执行此操作。任何指针都会有所帮助。感谢。

====
该表以时间为主键。

我有这个查询以正确的方式订购它(如果它有任何帮助)

按顺序选择oid,rev,state,time by orderid,time,rev

将给出:

oid rev州时间
    1 0 S T1
    1 0 A T3
    2 0 S T2
    2 0 A T4
    2 1 MS T5
    2 1 MA T6
    2 1 M T7
    2 2 MS T8
    2 2 M T9

这会有帮助吗?

1 个答案:

答案 0 :(得分:0)

嗯,我认为这是你应该在代码中做的事情,而不是你的数据库。

我可以想办法用SQL做到这一点,但它有点复杂。 它是这样的。假设您的原始表格为t1

  1. 创建一个视图,其中包含每个oid,rev。

    中的所有可能转换
    create view transitions as 
        select a.oid, a.rev, a.state as state_from, b.state as state_to, 
               a.time as time_from, b.time as time_to
        from t1 as a, t1 as b 
        where a.oid=b.oid 
          and a.rev=b.rev 
          and a.time<b.time; 
    
    
    +------+------+------------+----------+-----------+---------+
    | oid  | rev  | state_from | state_to | time_from | time_to |
    +------+------+------------+----------+-----------+---------+
    |    1 |    0 | S          | A        |        T1 |      T3 |
    |    2 |    0 | S          | A        |        T2 |      T4 |
    |    2 |    1 | MS         | MA       |        T5 |      T6 |
    |    2 |    1 | MS         | M        |        T5 |      T7 |
    |    2 |    1 | MA         | M        |        T6 |      T7 |
    |    2 |    2 | MS         | M        |        T8 |      T9 |
    +------+------+------------+----------+-----------+---------+
    
  2. 注意:此步骤不是必需的,但出于教育目的!)剪掉时间不连续的所有内容。它通过为每个time_to取最小time_from的行来实现此目的(因此需要T5->T6代替T5->T7

    select a.*
    from transitions as a
    join (
         select oid, rev, time_from, min(time_to) as time_to
         from transitions
         group by time_from
         ) as b 
         on a.oid=b.oid and a.rev=b.rev 
         and a.time_from=b.time_from and a.time_to=b.time_to;
    
    +------+------+------------+----------+-----------+---------+
    | oid  | rev  | state_from | state_to | time_from | time_to |
    +------+------+------------+----------+-----------+---------+
    |    1 |    0 | S          | A        |        T1 |     T3  |
    |    2 |    0 | S          | A        |        T2 |     T4  |
    |    2 |    1 | MS         | MA       |        T5 |     T6  |
    |    2 |    1 | MA         | M        |        T6 |     T7  |
    |    2 |    2 | MS         | M        |        T8 |     T9  |
    +------+------+------------+----------+-----------+---------+
    
  3. 现在您只想选择time_from-time_to其中state_fromstate_to是您感兴趣的转化。您可以将其与上一个查询结合使用,以便执行第2步。没有必要(步骤2中唯一新的东西是最后和/或/或位):

    select a.oid,a.rev,a.state_to as state,a.time_to-a.time_from as timeTaken
    from transitions as a
    join (
         select oid, rev, time_from, min(time_to) as time_to
         from transitions
         group by time_from
         ) as b 
         on a.oid=b.oid and a.rev=b.rev 
         and a.time_from=b.time_from and a.time_to=b.time_to
    and (   (a.state_from='S' and a.state_to='A')
         or (a.state_from='MS' and a.state_to='MA')
         or (a.state_from='MS' and a.state_to='M')
         );
    
    +------+------+-------+-----------+
    | oid  | rev  | state | timeTaken |
    +------+------+-------+-----------+
    |    1 |    0 | A     |   T3-T1   |
    |    2 |    0 | A     |   T4-T2   |
    |    2 |    2 | M     |   T6-T5   |
    |    2 |    1 | MA    |   T9-T8   |
    +------+------+-------+-----------+
    
  4. 总而言之,执行步骤1)一次创建视图,然后在每次需要执行计算时执行步骤3)。

    我敢打赌,有一种更有效的方法 - 这不是我的强项。 我认为执行join比将where子句全部移动更便宜,创建视图只是一次性成本。