6

Our workplace has started to scan all documents rather than manually keep them in archives etc.

On average we are scanning 1,000 documents per time (this happens about 30 times per day).

Each time we scan 1,000 documents we get a small amount of errors/warnings on OCR.

Is it possible to provide the lowest and highest order numbers in to a variable and get SQL server to output a list of all missing order numbers that are not in the table between the lowest and highest order numbers?

For example

OCROrderNo
---------------
9001
9002
9006
9007
9008
9009

Lowest number 9001, highest number 9009

MissingOrderNos
--------------------
9003
9094
9005

Additional information

As per the answer, this what I am attempting:

DECLARE @Start INT = 1497389
        , @End INT = 1498264

SELECT @Start + N - 1
FROM   dbo.Numbers
WHERE  N <= ( 1 + @End - @Start )
EXCEPT
SELECT [ORDERNUMBER]
FROM   [dwdata].[dbo].[ORDERS]
ORDER BY [ORDERNUMBER] DESC

Resulting in:

Msg 207, Level 16, State 1, Line 10
Invalid column name 'ORDERNUMBER'.

Msg 104, Level 16, State 1, Line 10
ORDER BY items must appear in the select list if the statement contains a UNION, INTERSECT or EXCEPT operator.

  • Well, I presume your table has a column named OCROrderNo, not ORDERNUMBER. You need to adjust the sample code to your own schema, which means correcting table and column names. – Aaron Bertrand Jul 2 '15 at 13:12
  • USe a column alias on the first SELECT .... e.g. SELECT @Start + N -1 AS [ORDERNUMBER]. – Mister Magoo Jul 2 '15 at 17:00
10

First create an auxiliary numbers table larger than the maximum range you will ever be interested in.

CREATE TABLE dbo.Numbers
(
N INT primary key
);   


WITH E00(N) AS (SELECT 1 UNION ALL SELECT 1),
    E02(N) AS (SELECT 1 FROM E00 a, E00 b),
    E04(N) AS (SELECT 1 FROM E02 a, E02 b),
    E08(N) AS (SELECT 1 FROM E04 a, E04 b),
    E16(N) AS (SELECT 1 FROM E08 a, E08 b),
    E32(N) AS (SELECT 1 FROM E16 a, E16 b),
cteTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY N) FROM E32)
INSERT 
INTO  dbo.Numbers
SELECT TOP(100000) N
FROM cteTally
OPTION (MAXDOP 1);

Then the query is simple

DECLARE @Start INT = 9001
        , @End INT = 9009

SELECT @Start + N - 1 AS ORDERNUMBER
FROM   dbo.Numbers
WHERE  N <= ( 1 + @End - @Start )
EXCEPT
SELECT [ORDERNUMBER]
FROM   [dwdata].[dbo].[ORDERS]
ORDER BY [ORDERNUMBER] DESC
0

Here is something to get you started. It will return a list with all missing Ids just like requested.

No need for other tables.

CREATE TABLE Numbers(n INT )
INSERT INTO Numbers SELECT 9001
INSERT INTO Numbers SELECT 9002
INSERT INTO Numbers SELECT 9006
INSERT INTO Numbers SELECT 9007
INSERT INTO Numbers SELECT 9008
INSERT INTO Numbers SELECT 9009

SELECT * FROM Numbers ORDER BY n

;WITH i AS
(
    SELECT LAG(n) OVER (ORDER BY n) AS PrevN
    ,n
    FROM Numbers
),
MissingList AS 
(
SELECT i.PrevN+1 AS MissingN, i.n-1 AS EndNum FROM i WHERE i.PrevN+1 <= i.n-1
    UNION ALL
    SELECT MissingN+1, EndNum FROM MissingList WHERE MissingN+1<=EndNum
)
SELECT MissingN AS MissingOrderNos FROM MissingList
WHERE MissingN BETWEEN 9001 AND 9009
ORDER BY MissingN
OPTION (maxrecursion 10000)

The result from the last sql is:

MissingOrderNos
---------------
9003
9004
9005
  • I renamed the table so you can see more clearly. The last select will return the wanted rowset. – SAS Jul 2 '15 at 13:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.