SQL - 如何获取完整的月份日历表

时间:2015-05-21 00:08:03

标签: sql sql-server

我需要生成一个报告,该报告将显示7个星期一到星期日和5个行,就像正常的月历一样:

enter image description here

我需要列表中的日期,所以欲望表结果应如下所示:

enter image description here

这样我的报表设计师就会自动创建如上所示的视图。

上面的表结果应该是动态生成的,不需要任何数据库表,因为在此之后我将不得不将日期连接到我的一个数据库表,这样我就可以填充我将用于的其他类型的信息在我的报告中显示每一天。

  

有任何线索吗?

6 个答案:

答案 0 :(得分:2)

任意日期序列的SQL小提琴,不需要表格。

http://sqlfiddle.com/#!3/9eecb7/275

DECLARE @dtStartDate datetime
DECLARE @dtEndDate datetime
SET @dtStartDate = '2015-05-01'
SET @dtEndDate = '2015-05-31'

SELECT
  CASE DATEPART(weekday, T.DateVal)
    WHEN 1 THEN 'Sunday'
    WHEN 2 THEN 'Monday'
    WHEN 3 THEN 'Tuesday'
    WHEN 4 THEN 'Wednesday'
    WHEN 5 THEN 'Thursday'
    WHEN 6 THEN 'Friday'
    WHEN 7 THEN 'Saturday'
  END AS WeekDay,
  DATEPART(day, T.DateVal) AS [Date],
  DATEPART(month, T.DateVal) AS [Month],
  DATEPART(year, T.DateVal) AS [Year]
FROM
(
  SELECT
      DATEADD(day, SEQ.SeqValue, @dtStartDate) DateVal
  FROM
  (
  SELECT
      (HUNDREDS.SeqValue + TENS.SeqValue + ONES.SeqValue) SeqValue
  FROM
      (
      SELECT 0  SeqValue
      UNION ALL
      SELECT 1 SeqValue
      UNION ALL
      SELECT 2 SeqValue
      UNION ALL
      SELECT 3 SeqValue
      UNION ALL
      SELECT 4 SeqValue
      UNION ALL
      SELECT 5 SeqValue
      UNION ALL
      SELECT 6 SeqValue
      UNION ALL
      SELECT 7 SeqValue
      UNION ALL
      SELECT 8 SeqValue
      UNION ALL
      SELECT 9 SeqValue
      ) ONES
  CROSS JOIN
      (
      SELECT 0 SeqValue
      UNION ALL
      SELECT 10 SeqValue
      UNION ALL
      SELECT 20 SeqValue
      UNION ALL
      SELECT 30 SeqValue
      UNION ALL
      SELECT 40 SeqValue
      UNION ALL
      SELECT 50 SeqValue
      UNION ALL
      SELECT 60 SeqValue
      UNION ALL
      SELECT 70 SeqValue
      UNION ALL
      SELECT 80 SeqValue
      UNION ALL
      SELECT 90 SeqValue
      ) TENS
  CROSS JOIN
      (
      SELECT 0 SeqValue
      UNION ALL
      SELECT 100 SeqValue
      UNION ALL
      SELECT 200 SeqValue
      UNION ALL
      SELECT 300 SeqValue
      UNION ALL
      SELECT 400 SeqValue
      UNION ALL
      SELECT 500 SeqValue
      UNION ALL
      SELECT 600 SeqValue
      UNION ALL
      SELECT 700 SeqValue
      UNION ALL
      SELECT 800 SeqValue
      UNION ALL
      SELECT 900 SeqValue
      ) HUNDREDS
  ) SEQ
) T
WHERE
  T.DateVal <= @dtEndDate
ORDER BY
  T.DateVal ASC

答案 1 :(得分:0)

编辑添加开始空白日期。如有必要,可以使用相同的逻辑附加空白日期。

declare @begindate date = '5-1-2015'
declare @enddate date = '6-1-2015'
create table MyCal (MyWeekday varchar(10), MyDate varchar(2), MyMonth varchar(10), MyYear int)

declare @DaysFromMonday int = 
    case datepart(weekday, @begindate)
    when 1 then 6
    else datepart(weekday, @begindate) - 2
    end

declare @datecounter date = dateadd(dd, -1* @daysFromMonday, @begindate)

while @datecounter < @enddate
begin
  insert into MyCal values (
      datename(weekday, @datecounter)
      , case when @datecounter < @begindate then '' else cast(datepart(DD, @datecounter) as varchar) end
      , datename(month, @datecounter)
      , datepart(YYYY, @datecounter)
  )
set @datecounter = dateadd(day, 1, @datecounter)
end

select * from MyCal

答案 2 :(得分:0)

您可以使用这段代码。 将#tmp表替换为您喜欢的正确表名。

declare @start_date datetime, @end_date datetime, @cur_date datetime

set @start_date = '2015-05-01'
set @end_date = '2016-04-30'
set @cur_date = @start_date

create table #tmp 
(weekday varchar(10), 
date int,
month varchar(10),
year int)

while @cur_date <= @end_date
begin

insert into #tmp
select datename(dw, @cur_date), datepart(day, @cur_date), datename(month, @cur_date), datepart(year, @cur_date)

set @cur_date = dateadd(dd, 1, @cur_date) 

end

select * from #tmp

drop table #tmp

答案 3 :(得分:0)

试试此版本 - 您必须一次运行一个月。如果这个月的最后一天不是星期天,我还添加了空白,例如试试他2015年8月。

declare @start_date datetime, @end_date datetime, @cur_date datetime

set @start_date = '2015-05-01'
set @end_date = '2015-05-31'
set @cur_date = @start_date

create table #tmp 
(weekday varchar(10), 
date varchar(2),
month varchar(10),
year int)


while datepart(dw, @cur_date) > 2
begin 

insert into #tmp
select datename(dw, dateadd(dd, -(datepart(dw, @cur_date) - 2), @start_date)), '', datename(month, @start_date), datepart(year, @start_date)

set @cur_date = dateadd(dd, -1, @cur_date) 

end

set @cur_date = @start_date

while @cur_date <= @end_date
begin

insert into #tmp
select datename(dw, @cur_date), datepart(day, @cur_date), datename(month, @cur_date), datepart(year, @cur_date)

set @cur_date = dateadd(dd, 1, @cur_date) 

end

set @cur_date = @end_date

while datepart(dw, @cur_date) > 1
begin 

insert into #tmp
select datename(dw, dateadd(dd, 1, @cur_date)), '', datename(month, @end_date), datepart(year, @end_date)

set @cur_date = dateadd(dd, 1, @cur_date) 

end


select * from #tmp

drop table #tmp

希望这有帮助。

答案 4 :(得分:0)

以下是使用multiple CTE查询和使用EMONTH SQL函数的SQL DATENAME月末函数的替代方法

declare @date as date = dateadd(mm,0,getdate())

;with monthdates as (
    SELECT dateadd(dd,1,EOMONTH(dateadd(mm,-1,@date))) firstofmonth, EOMONTH (@date) lastofmonth
), calc as (
    select
        firstofmonth, lastofmonth,
        dateadd(dd, 
                -1 * case when datepart(dw,firstofmonth)-2 >= 0 then datepart(dw,firstofmonth)-2 else datepart(dw,firstofmonth)+7-2 end,
                firstofmonth
                ) firstofcalendar,
        datediff(WEEK, 
                dateadd(dd, 
                        -1 * case when datepart(dw,firstofmonth)-2 >= 0 then datepart(dw,firstofmonth)-2 else datepart(dw,firstofmonth)+7-2 end,
                        firstofmonth
                        ),
                lastofmonth) weekcount
    from monthdates
), calendar1 as (
    select
        firstofcalendar,
        firstofmonth,
        lastofmonth,
        case when dateadd(dd, weekcount * 7 - 1, firstofcalendar) = lastofmonth then lastofmonth
        else
            dateadd(dd, (weekcount+1) * 7 - 1, firstofcalendar)
        end as lastofcalendar
    from calc
), calendar as (
select
    datename(dw,date) dayname,
    case when month(date) = month(@date) then cast(cast(date as date) as nvarchar) else '' end as date
from calendar1
cross apply [dbo].[DateTable](firstofcalendar, lastofcalendar)
)
select *, datename(mm,@date) month, datepart(yyyy,@date) year from calendar

答案 5 :(得分:-1)

这样的事应该适合你。它应该适用于您选择的任何一周开始:您只需要{/ 3}}连接/查询以适应。如果您希望星期一开始,请使用set datefirst 1

以下是查询:

set datefirst = 1 -- start the week on Monday

declare @month date = '1 May 2015'

;with
month_days as
(
  select dd = -5 union all
  select dd = -4 union all
  select dd = -3 union all
  select dd = -2 union all
  select dd = -1 union all
  select dd =  0 union all
  select dd =  1 union all
  select dd =  2 union all
  select dd =  3 union all
  select dd =  4 union all
  select dd =  5 union all
  select dd =  6 union all
  select dd =  7 union all
  select dd =  8 union all
  select dd =  9 union all
  select dd = 10 union all
  select dd = 11 union all
  select dd = 12 union all
  select dd = 13 union all
  select dd = 14 union all
  select dd = 15 union all
  select dd = 16 union all
  select dd = 17 union all
  select dd = 18 union all
  select dd = 19 union all
  select dd = 20 union all
  select dd = 21 union all
  select dd = 22 union all
  select dd = 23 union all
  select dd = 24 union all
  select dd = 25 union all
  select dd = 26 union all
  select dd = 27 union all
  select dd = 28 union all
  select dd = 29 union all
  select dd = 30 union all
  select dd = 31 union all
  select dd = 32 union all
  select dd = 33 union all
  select dd = 34 union all
  select dd = 35 union all
  select dd = 36 union all
  select dd = 37
),
calendar as
(
  select * ,
         yyyymmdd = dateadd(day,t.dd-1,@month)
  from month_days t
)
select Day_Of_Week = datename(weekday,c.yyyymmdd ) ,
       DD          = datepart(day   , c.yyyymmdd ) ,
       MM          = datepart(month , c.yyyymmdd ) ,
       YYYY        = datepart(year  , c.yyyymmdd )
from calendar c
where       datediff(month,@month,c.yyyymmdd) =  0                                        -- current month
   OR (     datediff(month,@month,c.yyyymmdd) <  0                                        -- previous month
        and datepart(weekday,c.yyyymmdd)      <  datepart(weekday,@month) )               -- ...to pad out the first week
   OR (     datediff(month,@month,c.yyyymmdd) >  0                                        -- next month
     and datepart(weekday,c.yyyymmdd)         >= datepart(weekday,dateadd(month,1,@month)) -- ... to pad out the last week
   )
order by c.yyyymmdd

运行上述查询会产生预期的

Day_Of_Week DD MM YYYY
=========== == == ====
Monday      27  4 2015
Tuesday     28  4 2015
Wednesday   29  4 2015
Thursday    30  4 2015
Friday       1  5 2015
Saturday     2  5 2015
Sunday       3  5 2015
Monday       4  5 2015
Tuesday      5  5 2015
Wednesday    6  5 2015
Thursday     7  5 2015
Friday       8  5 2015
Saturday     9  5 2015
Sunday      10  5 2015
Monday      11  5 2015
Tuesday     12  5 2015
Wednesday   13  5 2015
Thursday    14  5 2015
Friday      15  5 2015
Saturday    16  5 2015
Sunday      17  5 2015
Monday      18  5 2015
Tuesday     19  5 2015
Wednesday   20  5 2015
Thursday    21  5 2015
Friday      22  5 2015
Saturday    23  5 2015
Sunday      24  5 2015
Monday      25  5 2015
Tuesday     26  5 2015
Wednesday   27  5 2015
Thursday    28  5 2015
Friday      29  5 2015
Saturday    30  5 2015
Sunday      31  5 2015
Monday       1  6 2015
Tuesday      2  6 2015
Wednesday    3  6 2015
Thursday     4  6 2015
Friday       5  6 2015
Saturday     6  6 2015