Number sequences

Number sequences

Here is a quick look at number sequences, which are a brilliant (and fairly database neutral) method to create numbers (and rows) to build datasets from.

While working on the dates articles, I used number sequences a lot and thought they were worth coming back to.

What is a number sequence

A number sequence can be any series of numbers in a pattern. Here I’m talking about incrementing the number by 1 in each row. In many DBMS environments (SQL Server included) there is a row number metadata attribute which takes care of this. This method gives developers the opportunity to create rows from no existing data, and apply calculations to manipulate values.

For this sequence, I create a dataset with numbers 0 - 9, and then cartesian join that dataset to itself n times. This will create all numbers between 0 and (10n)-1. So, join the number table 3 times times for 0 - 999. See the below code example, I’ve made it deliberately verbose in nature to demonstrate the idea.

SQL Server (and MySQL with minimal changes)

--------------------------------------------------------------------------------
-- First get a recurring list of numbers
--------------------------------------------------------------------------------
WITH num_tbl AS (
SELECT 0 AS a UNION ALL
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5 UNION ALL
SELECT 6 UNION ALL
SELECT 7 UNION ALL
SELECT 8 UNION ALL
SELECT 9
)
SELECT t1.a
  FROM num_tbl t1
;

--------------------------------------------------------------------------------
-- Create a cartesian product
--------------------------------------------------------------------------------
WITH num_tbl AS (
SELECT 0 AS a UNION ALL
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5 UNION ALL
SELECT 6 UNION ALL
SELECT 7 UNION ALL
SELECT 8 UNION ALL
SELECT 9
)
SELECT t1.a AS t1a,
       t2.a AS t2a
 FROM num_tbl t1
  CROSS JOIN num_tbl t2
;

--------------------------------------------------------------------------------
-- Create a cartesian product (3 digits with calculation)
--------------------------------------------------------------------------------
WITH num_tbl AS (
SELECT 0 AS a UNION ALL
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5 UNION ALL
SELECT 6 UNION ALL
SELECT 7 UNION ALL
SELECT 8 UNION ALL
SELECT 9
)
SELECT t1.a AS t1a,
       t2.a AS t2a,
       t3.a AS t3a,
       (t1.a + (10 * t2.a) + (100 * t3.a)) AS concatenate_calculation
  FROM num_tbl t1
  CROSS JOIN num_tbl t2
  CROSS JOIN num_tbl t3
;

--------------------------------------------------------------------------------
-- Create Date list
--------------------------------------------------------------------------------
WITH number_tbl AS (
SELECT 0 AS a UNION ALL
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5 UNION ALL
SELECT 6 UNION ALL
SELECT 7 UNION ALL
SELECT 8 UNION ALL
SELECT 9
), number_sequences AS (
SELECT t1.a AS t1a,
       t2.a AS t2a,
       t3.a AS t3a,
       (t1.a + (10 * t2.a) + (100 * t3.a)) AS concatenate_calculation
  FROM number_tbl t1
  CROSS JOIN number_tbl t2
  CROSS JOIN number_tbl t3
)
SELECT t1a,
       t2a,
       t3a,
       concatenate_calculation,
       CAST(GetDate() AS DATE)                             AS todays_date_SQL_Server,
       CAST(GetDate() + (concatenate_calculation) AS DATE) AS calculated_date_range_SQL_Server
     /*CURDATE()                                           AS todays_date_MySQL,
       CAST(CURDATE() + (concatenate_calculation) AS DATE) AS calculated_date_range_MySQL */
  FROM number_sequences
 ORDER BY concatenate_calculation
;

Oracle

The method is the same, the key difference for oracle is the use of dual as a virtual table.

WITH number_tbl AS (
SELECT 0 AS a FROM dual UNION ALL
SELECT 1 AS a FROM dual UNION ALL
SELECT 2 AS a FROM dual UNION ALL
SELECT 3 AS a FROM dual UNION ALL
SELECT 4 AS a FROM dual UNION ALL
SELECT 5 AS a FROM dual UNION ALL
SELECT 6 AS a FROM dual UNION ALL
SELECT 7 AS a FROM dual UNION ALL
SELECT 8 AS a FROM dual UNION ALL
SELECT 9 AS a FROM dual
), number_sequences AS (
SELECT t1.a AS t1a,
       t2.a AS t2a,
       t3.a AS t3a,
       (t1.a + (10 * t2.a) + (100 * t3.a)) AS concatenate_calculation
  FROM number_tbl t1
  CROSS JOIN number_tbl t2
  CROSS JOIN number_tbl t3
)
SELECT t1a,
       t2a,
       t3a,
       concatenate_calculation,
     TRUNC(SysDate)                           AS todays_date_Oracle,
     TRUNC(SysDate) + concatenate_calculation AS calculated_date_range_Oracle
  FROM number_sequences
 ORDER BY concatenate_calculation
;

Manipulating the resultset

The resultset from this method is very simple, but can be used anywhere we want to create a sequence of numbers/rows:

  • Date range table
  • Medium/large dataset for testing

 

One Reply to “Number sequences”

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.