This is a good application for the structured part of structured query language.
I guess you will never have a value of seq
less than zero or greater than the arbitary value 15624
. That guess is important: we need a table of all the cardinal numbers in that range to get missing-number detection to work.
Here is such a table
SELECT A.N + 5*(B.N + 5*(C.N + 5*(D.N + 5*(E.N + 5*(F.N))))) AS seq
FROM (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) AS A
JOIN (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) AS B
JOIN (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) AS C
JOIN (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) AS D
JOIN (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) AS E
JOIN (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) AS F
(If you're using MariaDB, you can use the Sequence table seq_0_to_15624
in place of this lump of SQL code.)
Next, you need a way to find out the lowest and highest value of seq
for each part number. You do that like so.
SELECT partNumber, MIN(seq) minSeq, MAX(seq) maxSeq
FROM seq
GROUP BY partNumber
Next, you need to generate a table showing all the possible sequence numbers from minimum to maximum for each part number:
SELECT cardinals.seq, r.partNumber
FROM (
SELECT A.N + 5*(B.N + 5*(C.N + 5*(D.N + 5*(E.N + 5*(F.N))))) AS seq
FROM (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) AS A
JOIN (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) AS B
JOIN (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) AS C
JOIN (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) AS D
JOIN (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) AS E
JOIN (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) AS F
) cardinals
JOIN (
SELECT partNumber, MIN(seq) minSeq, MAX(seq) maxSeq
FROM seq
GROUP BY partNumber
) r ON cardinals.seq >= r.minSeq AND cardinals.seq <= r.maxSeq
Finally, you can LEFT JOIN that to your original table and do WHERE val IS NULL
to locate your missing sequence numbers.
SELECT cardinals.seq, r.partNumber
FROM (
SELECT A.N + 5*(B.N + 5*(C.N + 5*(D.N + 5*(E.N + 5*(F.N))))) AS seq
FROM (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) AS A
JOIN (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) AS B
JOIN (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) AS C
JOIN (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) AS D
JOIN (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) AS E
JOIN (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) AS F
) cardinals
JOIN (
SELECT partNumber, MIN(seq) minSeq, MAX(seq) maxSeq
FROM seq
GROUP BY partNumber
) r ON cardinals.seq >= r.minSeq AND cardinals.seq <= r.maxSeq
LEFT JOIN seq ON cardinals.seq = seq.seq AND r.PartNumber = seq.partNumber
WHERE seq.seq IS NULL