Skip to Main Content

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, dieter.

Asked: August 12, 2006 - 8:21 pm UTC

Last updated: November 01, 2021 - 4:07 am UTC

Version: 9.2.4

Viewed 10K+ times! This question is

You Asked

Hi Tom,

I have a simple SQL question on how to find gaps.
Immagine a table with a simple numeric primary key filled with from between id(100) to id(200) but having gaps.
How would I find the gaps wit a simple SQL statement?

Thank you

Dieter

and Tom said...

ops$tkyte%ORA10GR2> select * from t;

X
----------
1
2
5
6
7
10

6 rows selected.

ops$tkyte%ORA10GR2> select x, next_x
2 from (
3 select x, lead(x) over (order by x) next_x
4 from t
5 )
6 where x <> next_x-1
7 /

X NEXT_X
---------- ----------
2 5
7 10


Rating

  (10 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Could You elaborate over the sql

A reader, August 14, 2006 - 8:31 am UTC

Hi Tom

Excellent answer as usual - clear and precise.
Could You perhaps explain the sql shortly?



Tom Kyte
August 14, 2006 - 11:28 am UTC

search this site for:

analytics rock and roll


for plenty of examples - lead() is perhaps one of the easiest to understand here - basically "look forward a row", we keep rows where the difference between the current rows X and the next rows X (after sorting) is more than one.

Without Analytic Function

dieter, August 14, 2006 - 8:47 am UTC

Thank you !
Would you also know of a way to do this without analytic functions?

PS: I've just registred for you session in Vienna and am happy seeing you in Person in September.


Tom Kyte
August 14, 2006 - 11:42 am UTC

self joins
correlated subqueries (see below)
scalar subqueries

ops$tkyte%ORA9IR2> select *
  2    from (
  3  select x, (select min(x) from t t2 where t2.x > t.x) next_x
  4    from t
  5         )
  6   where x <> next_x-1
  7  /

         X     NEXT_X
---------- ----------
         2          5
         7         10


many ways, none as good as analytics though! 

Already answered

Tanmoy Choudhury, August 14, 2006 - 9:35 am UTC

Hey Tom,

I guess you have already answered that long back. I just remember the topic ..



Tom Kyte
August 14, 2006 - 11:43 am UTC

there are really only five or six questions on this site, the rest are variations on a theme

and the answer to the first three questions by the way is:

use bind variables.

Yes, Tom has answered a similar Question before

Pascal, August 14, 2006 - 10:00 am UTC

Hi Tom,

is this question similar to this thread?
http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:3225867788098

i tried to use the same logic from there, but it is not giving the correct missing values: 3,4,8,9,11

Example:

SQL> select * from t order by x;

         X
----------
         1
         2
         5
         6
         7
        10
        12
        13

SQL> select x+1
  2         from t
  3         where NOT EXISTS ( select null
  4                            from t t2
  5                            where t2.x = t.x+1 )
  6  order by x
  7  /

       X+1
----------
         3
         8
        11
        14
Using the Analytic approach correctly gives the expected missing Gap-Ranges:
SQL> select x, next_x
  2        from (
  3             select  x, lead(x) over (order by x) next_x
  4        from t
  5             )
  6  where x <> next_x-1
  7  /

         X     NEXT_X
---------- ----------
         2          5
         7         10
        10         12

However, how can i expand the missing gap ranges from the above Analytic approach into a List of Numbers:
3,4,8,9,11
 

Tom Kyte
August 14, 2006 - 11:50 am UTC

my query on that page found the first missing value

the analytics are useful for finding the entire range quite easily.

For Veinna

Riaz, August 14, 2006 - 10:02 am UTC

Following could be another approach (although it will not give you the same results as that of Tom's query..it will show the next missing no. only).


SQL> select a+1 from t t1
  2  where not exists(Select null from t t2 where t1.a+1 = t2.a);

       A+1
----------
         3
         8
        11 

MINUS ?

Colin 't Hart, August 14, 2006 - 11:46 am UTC

How about:

SQL> SELECT ROWNUM FROM dual CONNECT BY LEVEL <= 10 MINUS SELECT * FROM t;

    ROWNUM
----------
         3
         4
         8
         9

SQL> 

Tom Kyte
August 14, 2006 - 12:35 pm UTC

you'd have to make it "more generic" of course, you'd need to find the minimum ID, the maximum ID (in order to figure out how many ID's to generate), just rownum up to be the minimum id, and then minus.


it would work
it would not be a path I would consider however.

Alternate method

Geir K. Edland, September 15, 2006 - 7:31 am UTC

Several years back (1997) I solved a similar problem for a customer that needed a fast list (view) showing available phone numbers from a list of numbers where the used ones were removed. The list should present available numbers in ranges.
It was solved by the use of the pseudocolumn ROWNUM:

SELECT MIN(x) START_NO
,MAX(x) END_NO
FROM (SELECT X
,X+ROWNUM*(-1) RANGE_ID
FROM t)
GROUP BY RANGE_ID

Regards
G.Edland



Performance

Krous, September 28, 2006 - 1:40 pm UTC

I realise Analytics are much more efficient ( in cases where they make sense - much better than correlated sub-query here for example), but I have a hard time visualising how these work..

Do these functions actually read 2 rows for every row outputed? Do they store 2 lines in buffer so that when we need to output the next row, we dont have to do a read again?

Are there any docs which talk about how these analytics function work?

Tom Kyte
September 29, 2006 - 7:53 am UTC

well, my book expert one on one Oracle has what has been called a good chapter on this.

and there is a good chapter in the data warehousing guide for sql for analysis - it covers this as well.

Doh!

Krous, October 10, 2006 - 10:39 pm UTC

Have your Effective Oracle by Design and totally forgot about the other book that you wrote.. ( held up on buying it till your new version released and then just forgot.. (: )
Time to pony up and buy that and Cost-Based Oracle Fundamentals by Jonathan Lewis and get some reading done on the long flights. Now if only these were small paperback books that one can carry easily....

Still a great answer 15 years later

John Riggen, October 29, 2021 - 9:59 pm UTC

I just had to use this to analyze gaps in sequences in our test environment to avoid key clashes.
Connor McDonald
November 01, 2021 - 4:07 am UTC

Good SQL lasts forever :-)

More to Explore

Analytics

Analytic SQL got you confused? Check out Connor McDonald's complete video course.