查找字母数字序列中的缺失值

时间:2018-11-14 00:54:34

标签: mysql sql

我想识别字母数字序列中的缺失值。

该表的定义如下:

CREATE TABLE `seqtest` (
  `ID` int(11) NOT NULL,
  `PoleNo` text,
  `Pre` char(1) DEFAULT NULL,
  `Num` int(3) DEFAULT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

数据如下所示,并且始终是一个字母(A-Z),后跟000至999之间的三个数字。

| PoleNo |  Pre  |  Num  |
|------------------------|
| A000   |   A   |  000  |
| A001   |   A   |  001  |
| A002   |   A   |  002  |
| A004   |   A   |  003  |
| ****   |   *   |  ***  |
| A998   |   A   |  998  |
| A999   |   A   |  999  |
| B000   |   B   |  000  |
| B001   |   B   |  001  |
| B002   |   B   |  002  |
| ****   |   *   |  ***  |
| B998   |   B   |  998  |
| B999   |   B   |  999  |
| C000   |   C   |  000  |
| C001   |   C   |  001  |
| C005   |   C   |  005  |
| C006   |   C   |  006  |
|------------------------|

我希望查询发现例如缺少C002,C003和C004,如下所示。

|  Pre  | start | stop |
|   C   |   2   |   4  |
|----------------------|

我使用以下内容:

SELECT l.Pre, l.Num + 1 as start, min(fr.Num) - 1 as stop
FROM seqtest as l
    LEFT OUTER JOIN seqtest as r ON l.Num = r.Num - 1 AND l.Pre = r.Pre
    LEFT OUTER JOIN seqtest as fr ON l.Num < fr.Num AND l.Pre = fr.Pre
WHERE r.Num is null AND l.Num < 999
GROUP BY l.Pre, l.Num, r.Num

基于this

它给了我所缺少的范围,并且除了一种情况下效果很好之外……当“ Pre”从一个字母变为另一个字母时。

IE具有以下数据:

| PoleNo |  Pre  |  Num  |
|------------------------|
| B995   |   B   |  995  |
| B996   |   B   |  996  |
| B997   |   B   |  997  |
| C003   |   C   |  003  |
| C004   |   C   |  004  |
| C005   |   C   |  005  |
| C006   |   C   |  006  |
|------------------------| 

Id希望能够返回此值:

|  Pre  | start | stop |
|   B   |  998  |  999 |
|   C   |   0   |   2  |
|----------------------|

这可能吗?我使用PreNum字段,它们只是将PoleNo字段分解了...但是,如果有人发现仅使用PoleNo字段就可以做到这一点,也可以。

1 个答案:

答案 0 :(得分:0)

在MySQL 8+中,这要容易得多,因为您拥有lead()。但是,您可以按照自己的意愿做:

select st.pre,
       (st.num + 1) as start,
       (st.next_num - 1) as stop
from (select st.*,
             (select st2.num
              from seqtest st2
              where st2.pre = st.pre and
                    st2.num > st.num
              order by st2.num asc
              limit 1
             ) as next_num
      from seqtest st
     ) st
where next_num <> num + 1;

编辑:

这也将获得范围的开头和结尾:

select st.pre, 
       (st.num + 1) as start,
       (st.next_num - 1) as stop
from (select st.pre, num,
             coalesce( (select st2.num
                        from seqtest st2
                        where st2.pre = st.pre and
                              st2.num > st.num
                        order by st2.num asc
                        limit 1), 1000
                      ) as next_num
      from seqtest st
      union
      select st.pre, 0 as num, min(st.num) as next_num
      from seqtest st
      group by st.pre
     ) st
where next_num <> num + 1
order by pre, start;

Here是db <>小提琴。