Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8449489
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 10, 20262026-06-10T10:43:22+00:00 2026-06-10T10:43:22+00:00

In SQL For Smarties , Joe Celko provides an ANSI SQL definition of a

  • 0

In SQL For Smarties, Joe Celko provides an ANSI SQL definition of a Series table (elsewhere called Tally or Numbers). His definition ensures the values in the column are unique, positive and contiguous from 1 up to the maximum value:

CREATE TABLE Series (
  seq INTEGER NOT NULL PRIMARY KEY,
  CONSTRAINT non_negative_nbr CHECK (seq > 0),
  CONSTRAINT numbers_are_complete CHECK ((SELECT COUNT(*) FROM Series) = (SELECT MAX(seq) FROM Series))
);

Uniqueness is ensured by the PRIMARY KEY declaration. Positivity is ensured by the constraint non_negative_nbr. With these two constraints in place, contiguity is ensured by the constraint numbers_are_complete.

SQL Server does not support subqueries in check constraints. When I try to create the Series table, I receive an error like this:

Msg 1046, Level 15, State 1, Line 4
Subqueries are not allowed in this context. Only scalar expressions are allowed.
Msg 102, Level 15, State 1, Line 4
Incorrect syntax near ')'.

If I remove the unsupported constraint numbers_are_complete, I’m left with this definition:

CREATE TABLE Series (
  seq INTEGER NOT NULL PRIMARY KEY,
  CONSTRAINT non_negative_nbr CHECK (seq > 0)
);

When I try to create this version of Series, it succeeds:

Command(s) completed successfully.

This version of Series is weaker because it doesn’t enforce contiguity of the numbers in the table.

To demonstrate this, first I have to populate the table. I have adapted a technique described by Itzik Ben-Gan in his article ‘Virtual Auxiliary Table of Numbers‘ to do this efficiently for 65,536 rows:

WITH
N0(_) AS (SELECT NULL UNION ALL SELECT NULL),
N1(_) AS (SELECT NULL FROM N0 AS L CROSS JOIN N0 AS R),
N2(_) AS (SELECT NULL FROM N1 AS L CROSS JOIN N1 AS R),
N3(_) AS (SELECT NULL FROM N2 AS L CROSS JOIN N2 AS R),
N4(_) AS (SELECT NULL FROM N3 AS L CROSS JOIN N3 AS R)
INSERT INTO Series (
  seq
)
SELECT
  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS n
FROM N4;

The query produces output like this:

(65536 row(s) affected)

Now I can select from the table like this to produce 65,536 rows:

SELECT seq
FROM Series;

I’ve truncated the result set, but it looks like this:

seq
1
2
...
65535
65536

Check it for yourself, and you’ll see that every number in the interval [1, 65536] is in the result set. The series is contiguous.

But I can break contiguity by deleting any row that is not an endpoint of the range:

DELETE FROM Series
WHERE seq = 25788;

If contiguity were enforced, this statement would raise an error, but instead it succeeds:

(1 row(s) affected)

It would be difficult for a human to find the missing value by visual inspection. They would have to suspect that a value were missing in the first place before going to the trouble. For these reasons, tampering with the Series data is an easy way to introduce subtle bugs into an SQL Server application that relies on the Series table being contiguous.

Assume a user has written a query that reads from Sequence to enumerate rows from another source. After my tampering, that query would now produce incorrect results around a certain value – by the 25,788th row, everything is off by one.

It is possible to write a query to detect missing values in the Series table, but how do I constrain the table so that missing values are impossble?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-10T10:43:24+00:00Added an answer on June 10, 2026 at 10:43 am

    I have three potential suggestions:


    (1) Make your numbers table read-only (e.g. deny update/insert/delete). Why would you be deleting from this table, EVER? Your app certainly shouldn’t be doing it, and your users shouldn’t be able to manually do so either. No need for all these check constraints for users pressing the “what does this button do?” button, when you can simply remove the button.

    DENY DELETE ON dbo.Serial TO [your_app_user];
    -- repeat for individual users/roles
    

    (2) Even easier would be to create an instead of trigger to prevent deletes in the first place:

    CREATE TRIGGER dbo.LeaveMyNumbersAlone
    ON dbo.Serial
    INSTEAD OF DELETE
    AS
    BEGIN
      SET NOCOUNT ON;
      RAISERROR('Please leave my numbers table alone.', 11, 1);
    END
    

    Yes, this can be defeated, but someone has to really go out of their way to do it. And if you’re employing folks that are likely to do this, and trusting them with generic access to the database, pray that this is the most damage they’re planning to do.

    And yes, you might forget to re-implement the trigger if you drop / re-create the numbers table or implement it somewhere else. But you might also forget anything you might manually do to deal with gaps anyway.


    (3) You can avoid a numbers table altogether if you’re willing to derive numbers on the fly. I use catalog views like sys.all_columns and sys.all_objects for this, depending on how many numbers I need:

    ;WITH n AS (SELECT TOP (10000) n FROM 
      (SELECT n = ROW_NUMBER() OVER
        (ORDER BY s1.[object_id])
        FROM sys.all_objects AS s1
        CROSS JOIN sys.all_objects AS s2
      ) AS x ORDER BY n
    )
    SELECT n FROM n ORDER BY n; -- look ma, no gaps!
    

    If you only need 100 rows, you can just use one of the views without the cross join; if you need more, you can add more views. Not trying to push you away from a numbers table but this gets you around limitations such as (a) building a numbers table on every single instance and (b) people who are philosophically opposed to such a thing (I have come across many in my career).


    As an aside, this really should be in the product. Please vote and state real business use cases in the following Connect item:

    http://connect.microsoft.com/SQLServer/feedback/details/258733/add-a-built-in-table-of-numbers

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Hey smarties. I'm having trouble with the following SQL statement. I know that I
SQL novice here. I'm trying to get a list of invoice numbers. There are
SQL Server 2005 I have an SQL Function (ftn_GetExampleTable) which returns a table with
SQL Server 2005 Profiler shows that a Stored Procedure (SP) was called and what
SQL Server provides the type [rowguid]. I like to use this as unique primary
SQL Server 2008 R2: normally, we create our table, and stored procedure, and grant
SQL Server 2005/8 allows you to associate a synonym with a remote table (i.e.
SQL: CREATE TABLE IF NOT EXISTS `photoalbums` ( `id` int(11) NOT NULL AUTO_INCREMENT, `title`
SQL Server 2000 I have a table which lists out the months where a
SQL 2000 The NED table has a foreign key to the SIGN table NED.RowID

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.