Find missing values in an alphanumeric sequence
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
add a comment |
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
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
add a comment |
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
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
mysql sql
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
add a comment |
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
add a comment |
1 Answer
1
active
oldest
votes
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.
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
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
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
add a comment |
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.
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
add a comment |
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.
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.
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
add a comment |
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
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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