如何简化MySQL中的序列数据?

时间:2016-07-23 05:13:45

标签: mysql

之前我曾在How to get temporal sequence by mysql上提出问题。在那里,我希望得到一个带有最新日期的简化序列。 现在我想得到每个序列的开始日期和结束日期。假设表仍然是这样的:

ID    DATE    STATUS
1     0106      A
1     0107      A
1     0112      A
1     0130      B
1     0201      A
2     0102      C
2     0107      C

我希望得到这样的结果:

ID    START_DATE    END_DATE    STATUS
1       0106          0112        A
1       0130          0130        B
1       0201          0201        A
2       0102          0107        C

我试图改变前一个问题的答案,但失败了。我想知道我是如何实现它的。

2 个答案:

答案 0 :(得分:0)

哦,我刚刚想出了一个方法虽然看起来很愚蠢。该方法只是执行How to get temporal sequence by mysql的代码两次(按不同顺序)并加入这两个表。

答案 1 :(得分:0)

鉴于此

 SELECT * FROM T;
+------+------+--------+
| ID   | DATE | STATUS |
+------+------+--------+
|    1 |  106 | A      |
|    1 |  107 | A      |
|    1 |  112 | A      |
|    1 |  130 | B      |
|    1 |  201 | A      |
|    2 |  102 | C      |
|    2 |  107 | C      |
+------+------+--------+

使用此

分配块和seqno非常简单
SELECT  T.ID,T.DATE,T.STATUS,
            IF(STATUS <> @PREVS,@RN:=@RN+1,@RN:=@RN) RNBLOCK ,
            IF(STATUS = @PREVS,@RN2:=@RN2+1,@RN2:=1) RNSEQ ,
            @PREVS:=STATUS PSTATUS 
FROM        (SELECT @RN:=1) RNBLOCK, (SELECT @RN2:=0) RNSEQ,(SELECT @PREVS:=NULL) P, T

给这个

+------+------+--------+---------+-------+---------+
| ID   | DATE | STATUS | RNBLOCK | RNSEQ | PSTATUS |
+------+------+--------+---------+-------+---------+
|    1 |  106 | A      | 1       |     1 | A       |
|    1 |  107 | A      | 1       |     2 | A       |
|    1 |  112 | A      | 1       |     3 | A       |
|    1 |  130 | B      | 2       |     1 | B       |
|    1 |  201 | A      | 3       |     1 | A       |
|    2 |  102 | C      | 4       |     1 | C       |
|    2 |  107 | C      | 4       |     2 | C       |
+------+------+--------+---------+-------+---------+

所以现在我们已经隔离了块并且知道了最小序号no(1)和max seqno,我们可以将它们推入表中

drop table t1;
CREATE  TABLE `t1` (
    `ID` INT(11) NULL DEFAULT NULL,
    `DATE` INT(11) NULL DEFAULT NULL,
    `STATUS` VARCHAR(1) NULL DEFAULT NULL,
    `rnblock` int null default null,
    `rnseq` int null default null,
    `pstatus` VARCHAR(1) NULL DEFAULT NULL
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
;

并创建一个简单的最小连接

SELECT   T2.ID,T2.DATE,T3.DATE,T2.STATUS FROM
(       
SELECT   T1.RNBLOCK,MAX(T1.RNSEQ)  MAXSEQ
FROM        T1
GROUP       BY RNBLOCK
) S 
JOIN        T1 T2 ON T2.RNBLOCK = S.RNBLOCK AND T2.RNSEQ = 1
JOIN        T1 T3 ON T3.RNBLOCK = S.RNBLOCK AND T3.RNSEQ = S.MAXSEQ

得到这个

+------+------+------+--------+
| ID   | DATE | DATE | STATUS |
+------+------+------+--------+
|    1 |  106 |  112 | A      |
|    1 |  130 |  130 | B      |
|    1 |  201 |  201 | A      |
|    2 |  102 |  107 | C      |
+------+------+------+--------+

缺点是您必须创建一个表才能使其正常工作。

或者你可以使用这个相当笨拙的代码,它不使用中间表

select   u.id,u.date,v.date,u.status from
(
select   s.rnblock,s.status,min(s.rnseq) minseq,max(s.rnseq) maxseq
from
(
SELECT  T.ID,T.DATE,T.STATUS,
            IF(STATUS <> @PREVS,@RN:=@RN+1,@RN:=@RN) RNBLOCK ,
            IF(STATUS = @PREVS,@RN2:=@RN2+1,@RN2:=1) RNSEQ ,
            @PREVS:=STATUS PSTATUS 
FROM        (SELECT @RN:=1) RNBLOCK, (SELECT @RN2:=0) RNSEQ,(SELECT @PREVS:=NULL) P, T
) s
group       by s.rnblock,s.status
) T
join
(SELECT     T.ID,T.DATE,T.STATUS,
            IF(STATUS <> @PREVS2,@RN3:=@RN3+1,@RN3:=@RN3) RNBLOCK ,
            IF(STATUS = @PREVS2,@RN4:=@RN4+1,@RN4:=1) RNSEQ ,
            @PREVS2:=STATUS PSTATUS 
FROM        (SELECT @RN3:=1) RNBLOCK, (SELECT @RN4:=0) RNSEQ,(SELECT @PREVS2:=NULL) P, T
) u  on u.rnblock = t.rnblock and u.rnseq = minseq
join
(SELECT     T.ID,T.DATE,T.STATUS,
            IF(STATUS <> @PREVS3,@RN5:=@RN5+1,@RN5:=@RN5) RNBLOCK ,
            IF(STATUS = @PREVS3,@RN6:=@RN6+1,@RN6:=1) RNSEQ ,
            @PREVS3:=STATUS PSTATUS 
FROM        (SELECT @RN5:=1) RNBLOCK, (SELECT @RN6:=0) RNSEQ,(SELECT @PREVS3:=NULL) P, T
) v  on v.rnblock = t.rnblock and v.rnseq = maxseq