Anatoly Lubarsky Logo
programming, design, integration, games, music

T-SQL: Generate Sequences in a Loop Query

Sometimes there is a need to get calendar dates sequences of the year in useable format, for example table, so one can fetch data, search data, create joins and do other useful things, needed in processing application logic.


The common problem is when you need to get the dates sequences in a table format.


So, what can we do. Sometimes it is not efficient to store dates in the table prepared beforehand, because it uses space and some generation mechanism needed to create the dates sequences table beforehand. So we shall try to create such table on the fly. One can say - "big deal, I will create a loop and insert dates in the table of dates." Let's see some example:


DECLARE @gencalendar TABLE (cal_date DATETIME PRIMARY KEY)
DECLARE @p_date SMALLDATETIME

SET @p_date = '20040101'

WHILE @date <= '20041231'
BEGIN
    INSERT INTO @gencalendar(cal_date)
    VALUES(@p_date)

    SET @date = dateadd(d, 1, @p_date)
END

SELECT * 
  FROM @gencalendar

It works, but performance is not good. You know, it is not productive in SQL to make a loop and make many queries through the loop.


In T-SQL we can boost performance in this case by using a single query, that simulates a loop - a Loop Query. For example, consider the following query:


SELECT n3.num * 10 + n2.num mynumber
  FROM (SELECT 0 AS num 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) n2
      ,(SELECT 0 AS num UNION ALL
        SELECT 1 UNION ALL
        SELECT 2 UNION ALL
        SELECT 3) n3
 ORDER BY 1

This loop query returns a table of 40 ordered numbers from 0 to 39.


If we develop this idea a bit - we can achieve our desired result with sequence of calendar dates, using sequence loop queries. Let's see, what we get:


SELECT TOP 366 *
  FROM (SELECT CONVERT(SMALLDATETIME, '20040101') +
               n3.num * 100 +
               n2.num * 10 +
               n1.num AS CalendarDate
          FROM (SELECT 0 AS num 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) n1
              ,(SELECT 0 AS num 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) n2
              ,(SELECT 0 AS num UNION ALL
                SELECT 1 UNION ALL
                SELECT 2 UNION ALL
                SELECT 3) n3
       ) GenCalendar
 ORDER BY 1

We got our calendar dates sequence table. We will not stop at this point. Since we need this query for development, let's create UDF (user defined function) out of it and then use it in a single line of code.


CREATE FUNCTION F_GetCalendarTable
(@p_year smallint)
RETURNS @tbl TABLE (cal_date SMALLDATETIME)
AS
BEGIN
    -- 2 --
    DECLARE @p_start_date SMALLDATETIME
    SET @p_start_date = CONVERT(SMALLDATETIME, 
                        CONVERT(VARCHAR(4),@p_year) + '0101')
    -- 3 --
    INSERT INTO @tbl
    SELECT CalendarDate
      FROM (SELECT @p_start_date +
                   n3.num * 100 +
                   n2.num * 10 +
                   n1.num AS CalendarDate
              FROM (SELECT 0 AS num 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) n1
                  ,(SELECT 0 AS num 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) n2
                  ,(SELECT 0 AS num UNION ALL
                    SELECT 1 UNION ALL
                    SELECT 2 UNION ALL
                    SELECT 3) n3
                  ) GenCalendar
     ORDER BY 1

    RETURN
END

This function gets a year as an argument and returns a table of 400 dates. Let's say we need dates calendar table of 2004:


SELECT TOP 366 * 
  FROM dbo.GetCalendarTable(2004)

In conclusion I can say the following: the right use of a single loop query simulating sequences can boost performance (sometimes dramatically). Also it is useful to create tables on the fly when you have to deal with iterating, sequencing data such as calendar dates, sequence numbers, etc.


This article was published on sqljunkies.com


Related Posts:

Wednesday, March 24, 2004 3:52 AM

Comments

# re: T-SQL: Generate Dates Calendar (sqljunkies)
Awesome, of course not all years have 366 days. I'm trying to take your code even further. Is there a better way of Set a WeekEnd, than my union? I would like to add in Holidays http://usa.usembassy.de/holidays.htm with this new query, should be able to do it, Because we can find the Month/Week/and Day...

Create Function F_TBL_CALBREAKDOWN (@p_year smallint)
Returns @Cal table (WeekEnd bit)
as
begin
select * from (
select * from (
Select cal_date As Calendar,
DatePart(yy, cal_date) as 'Year',
DatePart(qq, cal_date) as 'Quarter',
DatePart(mm, cal_date) as 'Month',
DateName(mm, cal_date) as 'MonthName',
DatePart(dd, cal_date) as 'DayOfMonth',
DateName(dw, cal_date) as 'WeekDay',
DatePart(wk, cal_date) as 'Week',
DatePart(dy, cal_date) as 'DayOfTheYear',
Cast('0' as bit) as 'WeekEnd' From (
select top 366 * from F_TBL_CALENDAR(@p_year))as CalBreakDown) as AllDates
where (([WeekDay] <> 'Saturday') and ([WeekDay] <> 'Sunday'))
Union
select * from (
Select cal_date As Calendar,
DatePart(yy, cal_date) as 'Year',
DatePart(qq, cal_date) as 'Quarter',
DatePart(mm, cal_date) as 'Month',
DateName(mm, cal_date) as 'MonthName',
DatePart(dd, cal_date) as 'DayOfMonth',
DateName(dw, cal_date) as 'WeekDay',
DatePart(wk, cal_date) as 'Week',
DatePart(dy, cal_date) as 'DayOfTheYear',
Cast('1' as bit) as 'WeekEnd' From (
select top 366 * from F_TBL_CALENDAR(@p_year))as CalBreakDown) as FindWeek
where (([WeekDay] = 'Saturday') or ([WeekDay] = 'Sunday'))) as FixBug
where [Year] = @p_year)

10/4/2005 12:03 AM by Ken

# SQL query build calendar &laquo; Nathan
SQL query build calendar &laquo; Nathan

3/13/2012 4:46 PM by Pingback/TrackBack

Login

Subscribe via RSS

Article Categories

.Net Framework
ASP.NET Tips
C# Win32 API
HTML, CSS, Web
Javascript Tips
MSSQL Tips
System
System.Net
WebServices

Archives

(02) January 2018
(01) June 2013
(03) March 2013
(02) February 2013
(01) July 2012
(01) April 2012
(01) September 2011
(01) August 2011
(03) May 2011
(01) December 2010
(01) November 2010
(01) October 2010
(01) June 2010
(01) May 2010
(02) March 2010
(01) January 2010
(02) December 2009
(03) September 2009
(03) August 2009
(09) July 2009
(04) June 2009
(03) May 2009
(02) April 2009
(03) March 2009
(02) February 2009
(02) January 2009
(04) December 2008
(04) November 2008
(05) October 2008
(04) September 2008
(05) August 2008
(04) July 2008
(05) June 2008
(07) May 2008
(04) April 2008
(03) March 2008
(02) February 2008
(03) January 2008
(03) December 2007
(05) November 2007
(04) October 2007
(05) September 2007
(12) August 2007
(11) July 2007
(14) June 2007
(13) May 2007
(13) April 2007
(10) March 2007
(11) February 2007
(14) January 2007
(14) December 2006
(12) November 2006
(08) October 2006
(09) September 2006
(06) August 2006
(08) July 2006
(10) June 2006
(09) May 2006
(22) April 2006
(25) March 2006
(12) February 2006
(14) January 2006
(19) December 2005
(17) November 2005
(16) October 2005
(16) September 2005
(12) August 2005
(14) July 2005
(09) June 2005
(12) May 2005
(12) April 2005
(20) March 2005
(11) February 2005
(12) January 2005
(18) December 2004
(13) November 2004
(12) October 2004
(14) September 2004
(09) August 2004
(23) July 2004
(19) June 2004
(29) May 2004
(19) April 2004
(16) March 2004
(09) February 2004
(06) January 2004
(02) December 2003
(01) November 2003

Post Categories

.Net and C#
Android
Antispam
App. Development
Architecture
ASP.NET
Blogging
Deprecated Projects
Facebook Platform
Fun
Google
iOS
Javascript
Misc.
MSSQL
Music
My Games
Performance
Roller
Social Networks
Tools
Visual Studio
Web 2.0
WebServices

About Me

linkedin Profile
Recs
Who am I

My Sites

Billy Beet
x2line blogs