Find missing values in an alphanumeric sequence












0















I want to identify missing values in an alphanumeric sequence.



The table is defined as such:



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;


The data is as shown below and will always be one letter (A-Z) followed by three numbers from 000 to 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 |
|------------------------|


I want the query to find that, for example, C002, C003 AND C004 are missing as shown below.



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


Im using the following:



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


which is based on this.



It gives me the range that is missing and works well except for one case...when 'Pre' changes from one letter to the next.



IE With the following data:



| 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 like to be able to return this:



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


Is this possible? Im using the Pre and Num fields which are simply the PoleNo field broken up...but if anyone sees a way to do it just using the PoleNo field, that would work as well.










share|improve this question























  • What's your MySQL version?

    – D-Shih
    Nov 14 '18 at 1:33











  • My MySQL version is 5.5.14

    – Jon Henry
    Nov 14 '18 at 2:06











  • Can you setup a db-fiddle.com Real data would help in trying to fine tune the query.

    – Madhur Bhaiya
    Nov 15 '18 at 16:21
















0















I want to identify missing values in an alphanumeric sequence.



The table is defined as such:



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;


The data is as shown below and will always be one letter (A-Z) followed by three numbers from 000 to 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 |
|------------------------|


I want the query to find that, for example, C002, C003 AND C004 are missing as shown below.



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


Im using the following:



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


which is based on this.



It gives me the range that is missing and works well except for one case...when 'Pre' changes from one letter to the next.



IE With the following data:



| 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 like to be able to return this:



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


Is this possible? Im using the Pre and Num fields which are simply the PoleNo field broken up...but if anyone sees a way to do it just using the PoleNo field, that would work as well.










share|improve this question























  • What's your MySQL version?

    – D-Shih
    Nov 14 '18 at 1:33











  • My MySQL version is 5.5.14

    – Jon Henry
    Nov 14 '18 at 2:06











  • Can you setup a db-fiddle.com Real data would help in trying to fine tune the query.

    – Madhur Bhaiya
    Nov 15 '18 at 16:21














0












0








0








I want to identify missing values in an alphanumeric sequence.



The table is defined as such:



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;


The data is as shown below and will always be one letter (A-Z) followed by three numbers from 000 to 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 |
|------------------------|


I want the query to find that, for example, C002, C003 AND C004 are missing as shown below.



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


Im using the following:



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


which is based on this.



It gives me the range that is missing and works well except for one case...when 'Pre' changes from one letter to the next.



IE With the following data:



| 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 like to be able to return this:



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


Is this possible? Im using the Pre and Num fields which are simply the PoleNo field broken up...but if anyone sees a way to do it just using the PoleNo field, that would work as well.










share|improve this question














I want to identify missing values in an alphanumeric sequence.



The table is defined as such:



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;


The data is as shown below and will always be one letter (A-Z) followed by three numbers from 000 to 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 |
|------------------------|


I want the query to find that, for example, C002, C003 AND C004 are missing as shown below.



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


Im using the following:



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


which is based on this.



It gives me the range that is missing and works well except for one case...when 'Pre' changes from one letter to the next.



IE With the following data:



| 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 like to be able to return this:



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


Is this possible? Im using the Pre and Num fields which are simply the PoleNo field broken up...but if anyone sees a way to do it just using the PoleNo field, that would work as well.







mysql sql






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 14 '18 at 0:54









Jon HenryJon Henry

83




83













  • What's your MySQL version?

    – D-Shih
    Nov 14 '18 at 1:33











  • My MySQL version is 5.5.14

    – Jon Henry
    Nov 14 '18 at 2:06











  • Can you setup a db-fiddle.com Real data would help in trying to fine tune the query.

    – Madhur Bhaiya
    Nov 15 '18 at 16:21



















  • What's your MySQL version?

    – D-Shih
    Nov 14 '18 at 1:33











  • My MySQL version is 5.5.14

    – Jon Henry
    Nov 14 '18 at 2:06











  • Can you setup a db-fiddle.com Real data would help in trying to fine tune the query.

    – Madhur Bhaiya
    Nov 15 '18 at 16:21

















What's your MySQL version?

– D-Shih
Nov 14 '18 at 1:33





What's your MySQL version?

– D-Shih
Nov 14 '18 at 1:33













My MySQL version is 5.5.14

– Jon Henry
Nov 14 '18 at 2:06





My MySQL version is 5.5.14

– Jon Henry
Nov 14 '18 at 2:06













Can you setup a db-fiddle.com Real data would help in trying to fine tune the query.

– Madhur Bhaiya
Nov 15 '18 at 16:21





Can you setup a db-fiddle.com Real data would help in trying to fine tune the query.

– Madhur Bhaiya
Nov 15 '18 at 16:21












1 Answer
1






active

oldest

votes


















0














This is much easier in MySQL 8+, because you have lead(). But, you can do what you want as:



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;


EDIT:



This gets the ranges at the beginning and end as well:



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 is a db<>fiddle.






share|improve this answer


























  • Im sorry, but that does not work. My database contains 5935 records. Of them, A010, A011, B999, C000 and C001 are missing. The query you posted returns 5923 records. My query above returns A010, A011 and B999...Im only missing the C000 and C001.

    – Jon Henry
    Nov 14 '18 at 6:31











  • @JonHenry . . . Try it now. It comes much closer.

    – Gordon Linoff
    Nov 14 '18 at 13:30











  • I appreciate the help, but the query I originally posted already does that plus gets the B998. I just cant find a way to get the next C000 and C001 with it.

    – Jon Henry
    Nov 14 '18 at 15:20











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53291650%2ffind-missing-values-in-an-alphanumeric-sequence%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









0














This is much easier in MySQL 8+, because you have lead(). But, you can do what you want as:



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;


EDIT:



This gets the ranges at the beginning and end as well:



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 is a db<>fiddle.






share|improve this answer


























  • Im sorry, but that does not work. My database contains 5935 records. Of them, A010, A011, B999, C000 and C001 are missing. The query you posted returns 5923 records. My query above returns A010, A011 and B999...Im only missing the C000 and C001.

    – Jon Henry
    Nov 14 '18 at 6:31











  • @JonHenry . . . Try it now. It comes much closer.

    – Gordon Linoff
    Nov 14 '18 at 13:30











  • I appreciate the help, but the query I originally posted already does that plus gets the B998. I just cant find a way to get the next C000 and C001 with it.

    – Jon Henry
    Nov 14 '18 at 15:20
















0














This is much easier in MySQL 8+, because you have lead(). But, you can do what you want as:



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;


EDIT:



This gets the ranges at the beginning and end as well:



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 is a db<>fiddle.






share|improve this answer


























  • Im sorry, but that does not work. My database contains 5935 records. Of them, A010, A011, B999, C000 and C001 are missing. The query you posted returns 5923 records. My query above returns A010, A011 and B999...Im only missing the C000 and C001.

    – Jon Henry
    Nov 14 '18 at 6:31











  • @JonHenry . . . Try it now. It comes much closer.

    – Gordon Linoff
    Nov 14 '18 at 13:30











  • I appreciate the help, but the query I originally posted already does that plus gets the B998. I just cant find a way to get the next C000 and C001 with it.

    – Jon Henry
    Nov 14 '18 at 15:20














0












0








0







This is much easier in MySQL 8+, because you have lead(). But, you can do what you want as:



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;


EDIT:



This gets the ranges at the beginning and end as well:



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 is a db<>fiddle.






share|improve this answer















This is much easier in MySQL 8+, because you have lead(). But, you can do what you want as:



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;


EDIT:



This gets the ranges at the beginning and end as well:



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 is a db<>fiddle.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 14 '18 at 13:37

























answered Nov 14 '18 at 3:57









Gordon LinoffGordon Linoff

770k35304404




770k35304404













  • Im sorry, but that does not work. My database contains 5935 records. Of them, A010, A011, B999, C000 and C001 are missing. The query you posted returns 5923 records. My query above returns A010, A011 and B999...Im only missing the C000 and C001.

    – Jon Henry
    Nov 14 '18 at 6:31











  • @JonHenry . . . Try it now. It comes much closer.

    – Gordon Linoff
    Nov 14 '18 at 13:30











  • I appreciate the help, but the query I originally posted already does that plus gets the B998. I just cant find a way to get the next C000 and C001 with it.

    – Jon Henry
    Nov 14 '18 at 15:20



















  • Im sorry, but that does not work. My database contains 5935 records. Of them, A010, A011, B999, C000 and C001 are missing. The query you posted returns 5923 records. My query above returns A010, A011 and B999...Im only missing the C000 and C001.

    – Jon Henry
    Nov 14 '18 at 6:31











  • @JonHenry . . . Try it now. It comes much closer.

    – Gordon Linoff
    Nov 14 '18 at 13:30











  • I appreciate the help, but the query I originally posted already does that plus gets the B998. I just cant find a way to get the next C000 and C001 with it.

    – Jon Henry
    Nov 14 '18 at 15:20

















Im sorry, but that does not work. My database contains 5935 records. Of them, A010, A011, B999, C000 and C001 are missing. The query you posted returns 5923 records. My query above returns A010, A011 and B999...Im only missing the C000 and C001.

– Jon Henry
Nov 14 '18 at 6:31





Im sorry, but that does not work. My database contains 5935 records. Of them, A010, A011, B999, C000 and C001 are missing. The query you posted returns 5923 records. My query above returns A010, A011 and B999...Im only missing the C000 and C001.

– Jon Henry
Nov 14 '18 at 6:31













@JonHenry . . . Try it now. It comes much closer.

– Gordon Linoff
Nov 14 '18 at 13:30





@JonHenry . . . Try it now. It comes much closer.

– Gordon Linoff
Nov 14 '18 at 13:30













I appreciate the help, but the query I originally posted already does that plus gets the B998. I just cant find a way to get the next C000 and C001 with it.

– Jon Henry
Nov 14 '18 at 15:20





I appreciate the help, but the query I originally posted already does that plus gets the B998. I just cant find a way to get the next C000 and C001 with it.

– Jon Henry
Nov 14 '18 at 15:20


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53291650%2ffind-missing-values-in-an-alphanumeric-sequence%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

The Sandy Post

Danny Elfman

Pages that link to "Head v. Amoskeag Manufacturing Co."