TSQL table variable initialization
Asked Answered
G

5

17

I have the following TSQL table variable:

declare @NumDaysMonth table
(
   month_id smallint,
   num_days smallint
)

I just want a quick look-up for the number of days in each month. How can I initialize this table like a C array:

int numDaysMonth[] = {31, 28, 30, ... , 31};
Gorget answered 25/9, 2012 at 18:48 Comment(1)
Of course, if this is anything other than just an example, you do remember that February has 28 or 29 days in it, depending upon if it's a leap year, right?Numerate
D
29

Well you can't. The best you can do is something like this

Insert Into @NumDaysMonth
Values 
(1,31),
(2,28),
(3,31),
...
(12,31);

Then retrieval might be something like

DECLARE @LookItUp int

SELECT @LookItUp = num_days 
FROM @NumDaysMonth
WHERE month_Id = 12;

PRINT @LookItUp 

SQL Fiddle Demo

Devotee answered 25/9, 2012 at 18:51 Comment(2)
Actually, based on your answer, I would say that you can, it just has a different syntax, and the index isn't implied like in C.Heimer
"Well you can't" - yes you can. See my answer.Dagall
K
3

The following does not address the OP's question of initializing a table. You are welcome to treat it as a formatted comment.

A trick that is handy for the odd lookup table is to create a virtual table on the fly:

declare @Foo as Table ( Month Int )
insert into @Foo values ( 1 ), ( 3 ), ( 9 )

select *
  from @Foo as F inner join
    ( select month_id, num_days
      from ( values
      ( 1, 31 ), ( 2, 28 ), ( 3, 31 ), ( 4, 30 ), ( 5, 31 ), ( 6, 30 ),
      ( 7, 31 ), ( 8, 31 ), ( 9, 30 ), ( 10, 31 ), ( 11, 30 ), ( 12, 31 )
      ) as NumDaysMonth( month_id, num_days ) ) as NumDaysMonth on
    NumDaysMonth.month_id = F.Month

For getting the number of days in a month I would be more inclined to create a function that takes the year and month and returns the correct value. When I need a quick one off translation from some code to something readable the un-table is convenient.

If you need to refer to the faux table a few times in one place:

; with NumDaysMonth as (
  ( select month_id, num_days
    from ( values
      ( 1, 31 ), ( 2, 28 ), ( 3, 31 ), ( 4, 30 ), ( 5, 31 ), ( 6, 30 ),
      ( 7, 31 ), ( 8, 31 ), ( 9, 30 ), ( 10, 31 ), ( 11, 30 ), ( 12, 31 )
      ) as NumDaysMonth( month_id, num_days ) ) ),
  FooMonths as (
    select *
      from @Foo as F inner join
        NumDaysMonth as NDM on NDM.month_id = F.Month ),
  FooWithFollowingMonths as (
    select *
      from FooMonths
    union
    select *
      from @Foo as F inner join
        NumDaysMonth as NDM on NDM.month_id = F.Month + 1 )
  select *
    from FooWithFollowingMonths

Beyond that the lookup table should probably be kept as a real table or table valued function.

Krystinakrystle answered 25/9, 2012 at 19:52 Comment(0)
A
2

FYI that sort of array is a bit incomplete since it doesn't change with leap years? e.g. there are 29 days in February this year.

The following gives you a list that is 0-indexed (like C#) and is for the current year.

declare @NumDaysMonth table
(
   month_id smallint,
   num_days smallint
)
insert @NumDaysMonth
select m.m, day(dateadd(m,m+1,y)-1)
from
(select CAST(right(year(getdate()),4)+'0101' as datetime)) y(y)
cross join
(select 0 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 union all
 select 10 union all
 select 11) m(m)

select * from @NumDaysMonth

-- results
MONTH_ID    NUM_DAYS
0   31
1   29
2   31
3   30
4   31
5   30
6   31
7   31
8   30
9   31
10  30
11  31

If you need it for any other year, put the year into the Y subquery, e.g. (select cast('19990101' as datetime))

Azotobacter answered 25/9, 2012 at 20:6 Comment(0)
D
2

It's easy. Use identity to generate an automatically incrementing number.

declare @NumDaysMonth table
(
    month_id smallint identity primary key,
    num_days smallint
);

insert into @NumDaysMonth
    (num_days)
values
    (31),
    (28),
    (31),
    (30),
    (31),
    (30),
    (31),
    (31),
    (30),
    (31),
    (30),
    (31);

select *
from @NumDaysMonth;

->

(12 row(s) affected)
month_id num_days
-------- --------
1        31
2        28
3        31
4        30
5        31
6        30
7        31
8        31
9        30
10       31
11       30
12       31

(12 row(s) affected)

identity can be seeded with a different starting number or increment if required.

Dagall answered 21/6, 2016 at 15:8 Comment(0)
M
0

Can use UDF instead and make it adjustable for any year.

-- =============================================
-- Author:      Alexander Melnichuk for StackOverflow.com
-- Create date: 2013-03-12
-- Description: Number of days in a month
-- =============================================
CREATE FUNCTION [dbo].[f_NumDaysMonth] (
    @Year datetime = NULL   -- Month and day are ignored. Null gets current year. 
)
RETURNS 
@Ret TABLE (
    month_id smallint, 
    num_days smallint
)
AS
BEGIN
    SET @Year = convert(datetime, convert(varchar(4), 
                    isnull(@Year, getdate()), 112) + '0101', 112)

    WITH  
    seq AS  
    (--==== Returns table of values from 1 to 12
    SELECT TOP (12)
        N = ROW_NUMBER() OVER (ORDER BY t1.Object_ID)
    FROM Master.sys.All_Columns t1          -- There are certainly more than 12 columns in your Master database ;)
    --CROSS JOIN Master.sys.All_Columns t2  -- Uncomment if you need more values. Not this time though.
    )  

    INSERT INTO @Ret
    SELECT N, 
        day(dateadd(day, -1, dateadd(month, N, @Year)))
    FROM seq
    RETURN 
END

Usage:

SELECT * FROM [dbo].[f_NumDaysMonth] ('20130101')

Execution time - 0 ms. :)

Michele answered 12/3, 2013 at 13:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.