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

How to simplify sequence data in MySQL?

我之前在 上问过一个问题。在那里我想得到一个最新日期的简化序列。 现在我想获取每个序列的开始日期和结束日期。假设table还是这样:

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

虽然我尝试将前一个问题的答案适应它但失败了。我想知道如何实现它。

哦,我刚刚想到了一个方法,虽然看起来很笨。该方法只是执行 中的代码两次(按不同的顺序)并连接这两个表。

鉴于此

 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       |
+------+------+--------+---------+-------+---------+

所以现在我们已经隔离了块并知道了最小序列号 (1) 和最大序列号,我们可以将它们推入 table

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      |
+------+------+------+--------+

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

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

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