一个月的第N周的SQL第N天 [英] SQL Nth Day of Nth Week of a Month

查看:175
本文介绍了一个月的第N周的SQL第N天的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用以下功能来安排每月按照月份的星期和工作日进行的俱乐部会议。在下面的示例中,我有一个(将要)的函数返回本月的第三个星期三。如果那天发生在过去,那么它将在下个月的第三个星期三返回。

I want to use the following function for scheduling club meetings which occur on a monthly basis based on the week and weekday of the month. In the example below I have a (to be) function that returns the Third Wednesday of the month. If that day occurs in the past then it returns the next month's 3rd Wednesday.

我想离开循环,我觉得有一个更好的计算方法。是否有更多的OO流程?您的意见?

I want to get away from the Loops and I feel that there is a better method for calculation. Is there a more OO process? Your opinion?

--CREATE FUNCTION NextWeekDayofMonth

DECLARE 
--(
        @WEEK INT,
        @WEEKDAY INT,
        @REFERENCEDATE DATETIME
--) 
--RETURNS DATETIME
--AS

-------------------------------
--Values for testing - Third Wednesday of the Month
set @WEEK = 3   --Third Week
set @WEEKDAY = 4    --Wednesday
set @REFERENCEDATE = '08/20/2011'
-------------------------------

BEGIN

    DECLARE @WEEKSEARCH INT
    DECLARE @FDOM DATETIME
    DECLARE @RETURNDATE DATETIME
    SET @FDOM = DATEADD(M,DATEDIFF(M,0,@REFERENCEDATE),0)
    SET @RETURNDATE = DATEADD(M,0,@FDOM)


    WHILE (@RETURNDATE < @REFERENCEDATE)
    --If the calculated date occurs in the past then it 
    --finds the appropriate date in the next month
    BEGIN

    SET @WEEKSEARCH = 1
    SET @RETURNDATE = @FDOM

    --Finds the first weekday of the month that matches the provided weekday value
        WHILE ( DATEPART(DW,@RETURNDATE) <> @WEEKDAY)
            BEGIN
            SET @RETURNDATE = DATEADD(D,1,@RETURNDATE)
            END

    --Iterates through the weeks without going into next month
        WHILE @WEEKSEARCH < @WEEK
            BEGIN
            IF MONTH(DATEADD(WK,1,@RETURNDATE)) = MONTH(@FDOM) 
                BEGIN
                    SET @RETURNDATE = DATEADD(WK,1,@RETURNDATE)
                    SET @WEEKSEARCH = @WEEKSEARCH+1
                END 
                ELSE
                    BREAK
            END
        SET @FDOM = DATEADD(M,1,@FDOM)
    END

    --RETURN @RETURNDATE
    select @ReturnDate
    END


推荐答案

IMO,最好的过程是将重要的业务信息存储在数据库表中的行中。如果你建立一个日历表,你可以通过一个简单的查询获得所有的第三个星期三。

IMO, the best process is to store important business information as rows in tables in a database. If you build a calendar table, you can get all the third Wednesdays by a simple query. Not only are the queries simple, they can be seen to be obviously correct.

select cal_date 
from calendar
where day_of_week_ordinal = 3
  and day_of_week = 'Wed';

今天或之后的第三个星期三也很简单。

The third Wednesday that's on or after today is also simple.

select min(cal_date)
from calendar
where day_of_week_ordinal = 3
  and day_of_week = 'Wed'
  and cal_date >= CURRENT_DATE;

创建日历表很简单。这是为PostgreSQL编写的,但它是完全标准的SQL(我认为),除了与ISO年和ISO周相关的列。

Creating a calendar table is straightforward. This was written for PostgreSQL, but it's entirely standard SQL (I think) except for the columns relating to ISO years and ISO weeks.

create table calendar (
  cal_date date primary key,
  year_of_date integer not null 
    check (year_of_date = extract(year from cal_date)),
  month_of_year integer not null 
    check (month_of_year = extract(month from cal_date)),
  day_of_month integer not null 
    check (day_of_month = extract(day from cal_date)),
  day_of_week char(3) not null 
    check (day_of_week = 
    case when extract(dow from cal_date) = 0 then 'Sun'
         when extract(dow from cal_date) = 1 then 'Mon'
         when extract(dow from cal_date) = 2 then 'Tue'
         when extract(dow from cal_date) = 3 then 'Wed'
         when extract(dow from cal_date) = 4 then 'Thu'
         when extract(dow from cal_date) = 5 then 'Fri'
         when extract(dow from cal_date) = 6 then 'Sat'
    end),
  day_of_week_ordinal integer not null
    check (day_of_week_ordinal = 
      case
        when day_of_month >= 1 and day_of_month <= 7 then 1
        when day_of_month >= 8 and day_of_month <= 14 then 2
        when day_of_month >= 15 and day_of_month <= 21 then 3
        when day_of_month >= 22 and day_of_month <= 28 then 4
        else 5
      end),
  iso_year integer not null 
    check (iso_year = extract(isoyear from cal_date)),
  iso_week integer not null 
    check (iso_week = extract(week from cal_date))
);

您可以使用电子表格或UDF填充该表。电子表格通常具有非常好的日期和时间功能。我有一个UDF,但它是为PostgreSQL(PL / PGSQL)编写的,所以我不知道它可以帮助你多少。但如果你愿意,我会稍后再发布。

You can populate that table with a spreadsheet or with a UDF. Spreadsheets usually have pretty good date and time functions. I have a UDF, but it's written for PostgreSQL (PL/PGSQL), so I'm not sure how much it would help you. But I'll post it later if you like.

这篇关于一个月的第N周的SQL第N天的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆