Anatoly Lubarsky Logo
MSSQL, .NET, Design. Life and 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

Login

Fosimo
Get Fosimo on CNET Download.com!
Fosimo.TR
Get Fosimo.TR from CNET Download.com!
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) March, 2010
(01) January, 2010
(02) December, 2009
(03) September, 2009
(03) August, 2009
(09) July, 2009
(04) June, 2009
(04) May, 2009
(02) April, 2009
(05) March, 2009
(03) February, 2009
(03) January, 2009
(06) December, 2008
(04) November, 2008
(06) October, 2008
(07) September, 2008
(09) August, 2008
(05) July, 2008
(05) June, 2008
(07) May, 2008
(06) April, 2008
(03) March, 2008
(02) February, 2008
(04) January, 2008
(03) December, 2007
(05) November, 2007
(06) October, 2007
(07) September, 2007
(13) August, 2007
(11) July, 2007
(14) June, 2007
(16) May, 2007
(14) April, 2007
(10) March, 2007
(17) February, 2007
(21) January, 2007
(17) December, 2006
(14) November, 2006
(13) October, 2006
(13) September, 2006
(14) August, 2006
(12) July, 2006
(11) June, 2006
(12) May, 2006
(22) April, 2006
(36) March, 2006
(14) February, 2006
(14) January, 2006
(20) December, 2005
(17) November, 2005
(17) October, 2005
(17) September, 2005
(14) August, 2005
(18) July, 2005
(12) June, 2005
(17) May, 2005
(13) April, 2005
(22) March, 2005
(12) February, 2005
(14) January, 2005
(19) December, 2004
(15) November, 2004
(13) October, 2004
(16) September, 2004
(12) August, 2004
(29) July, 2004
(25) June, 2004
(33) May, 2004
(26) April, 2004
(18) March, 2004
(11) February, 2004
(07) January, 2004
(03) December, 2003
(02) November, 2003

Post Categories

.Net and C#
Antispam
App. Development
Architecture
ASP.NET
Blogging
del.icio.us
Fosimo
Fun
Google
Javascript
Misc.
MSSQL
Music
Performance
Roller
Social Networks
Tools
Visual Studio
Web 2.0
WebServices
Yahoo

About Me

linkedin Profile
Recs
Recs Books
Who am I

My Sites

onecone
x2line blogs