使用 SQL 将月末关闭业务日期分组到一个桶中
Grouping Month End Close Business Dates into a bucket using SQL
我目前正在使用这个逻辑来计算这些月底的结束日期
(定义为当月最后一个工作日、下个月第一个工作日和下个月第二个工作日)
SELECT
CASE
WHEN DATE_VALUE IN
(
SELECT DATE_VALUE
FROM (
SELECT ROW_NUMBER() OVER ( PARTITION BY FIRST_DAY_OF_CALENDAR_MONTH_DATE ORDER BY DAY_NUMBER_IN_MONTH ) AS [MEC1],
ROW_NUMBER() OVER ( PARTITION BY FIRST_DAY_OF_CALENDAR_MONTH_DATE ORDER BY DAY_NUMBER_IN_MONTH ) AS [MEC2] ,
ROW_NUMBER() OVER ( PARTITION BY FIRST_DAY_OF_CALENDAR_MONTH_DATE ORDER BY DAY_NUMBER_IN_MONTH DESC ) AS [MEC3] ,
DATE_VALUE
FROM DATE_DIM
WHERE RELATIVE_MONTH BETWEEN -13 AND 0
AND WEEK_DAY_IND = 1
AND COMPANY_HOLIDAY_IND = 0
) d
WHERE MEC1 = 1 -- To get First Day of Business Month
OR MEC2 = 2 -- To get Second Day of Business Month
OR MEC3 = 1 -- To get Last Day of Business Month
) THEN 1
ELSE 0
END AS [MEC_IND]
然后我选择 [MEC_IND] = 1
的日期
SELECT
Date_Value,
FIRST_DAY_OF_CALENDAR_MONTH_DATE
FROM ...
WHERE C.MEC_IND = 1
使用这种逻辑,我设法以这种方式获取日期,
我如何修改逻辑以将这些月末关闭业务日期分组到像这样的桶中
请记住,我使用的是 SQL Server 2008,无法使用 LEAD 和 LAG 功能。
有人可以指导我吗?任何帮助将不胜感激。提前致谢。
我能想到的最直接的方法是使用 dateadd()
和 case
表达式来根据 day()
添加一个或零个月并将结果截断到月初。
在此示例中使用临时日期 table:
declare @fromdate date = '20170428'
declare @thrudate date = '20170704'
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
, dates as (
select top (datediff(day, @fromdate, @thrudate)+1)
[Date]=convert(date,dateadd(day,row_number() over(order by (select 1))-1,@fromdate))
from n as deka cross join n as hecto cross join n as kilo
cross join n as tenK cross join n as hundredK
order by [Date]
)
select
date = [Date]
, EffectiveMonth = dateadd(month
, datediff(month, 0
, dateadd(month,case when day(date) > 27 then 1 else 0 end, [Date])
)
, 0)
from dates
where day(date) <4 or day(date) > 27; -- for brevity in results
rextester 演示:http://rextester.com/HJXXYL94271
returns:
+------------+----------------+
| date | EffectiveMonth |
+------------+----------------+
| 2017-04-28 | 2017-05-01 |
| 2017-04-29 | 2017-05-01 |
| 2017-04-30 | 2017-05-01 |
| 2017-05-01 | 2017-05-01 |
| 2017-05-02 | 2017-05-01 |
| 2017-05-03 | 2017-05-01 |
| 2017-05-28 | 2017-06-01 |
| 2017-05-29 | 2017-06-01 |
| 2017-05-30 | 2017-06-01 |
| 2017-05-31 | 2017-06-01 |
| 2017-06-01 | 2017-06-01 |
| 2017-06-02 | 2017-06-01 |
| 2017-06-03 | 2017-06-01 |
| 2017-06-28 | 2017-07-01 |
| 2017-06-29 | 2017-07-01 |
| 2017-06-30 | 2017-07-01 |
| 2017-07-01 | 2017-07-01 |
| 2017-07-02 | 2017-07-01 |
| 2017-07-03 | 2017-07-01 |
+------------+----------------+
要分解表达式,组合的主要两个部分是 dateadd()
,它使用 case
表达式来确定是否应添加月份(对于该月的最后一个工作日)(每月的第一个工作日)和日期截断。
带有case
表达式的dateadd()
是:
dateadd(month
, case when day(date) > 27 then 1 else 0 end
, [Date])
将日期截断到该月的第一天很简单,但语法可能不直观。将自 1900-01-01
以来的月数添加到日期 1900-01-01
可以让我们将日期截断到月初。
例如,对于当前日期:
select dateadd(month, datediff(month, 0, getdate() ), 0)
同一表达式的注释版本:
select dateadd(month
, datediff(month
, 0 /* '19000101' */
, getdate() /* date */
) /* end of datediff, returns integer number of months */
, 0 /* '19000101' */
)
将日期截断与我们用 case 表达式导出的日期组合起来,结果如下:
select dateadd(month
, datediff(month
, 0 /* '19000101' */
, dateadd(month
, case when day([Date]) > 27 then 1 else 0 end
, [Date]) /* date */
) /* end of datediff, returns integer number of months */
, 0 /* '19000101' */
)
我目前正在使用这个逻辑来计算这些月底的结束日期
(定义为当月最后一个工作日、下个月第一个工作日和下个月第二个工作日)
SELECT
CASE
WHEN DATE_VALUE IN
(
SELECT DATE_VALUE
FROM (
SELECT ROW_NUMBER() OVER ( PARTITION BY FIRST_DAY_OF_CALENDAR_MONTH_DATE ORDER BY DAY_NUMBER_IN_MONTH ) AS [MEC1],
ROW_NUMBER() OVER ( PARTITION BY FIRST_DAY_OF_CALENDAR_MONTH_DATE ORDER BY DAY_NUMBER_IN_MONTH ) AS [MEC2] ,
ROW_NUMBER() OVER ( PARTITION BY FIRST_DAY_OF_CALENDAR_MONTH_DATE ORDER BY DAY_NUMBER_IN_MONTH DESC ) AS [MEC3] ,
DATE_VALUE
FROM DATE_DIM
WHERE RELATIVE_MONTH BETWEEN -13 AND 0
AND WEEK_DAY_IND = 1
AND COMPANY_HOLIDAY_IND = 0
) d
WHERE MEC1 = 1 -- To get First Day of Business Month
OR MEC2 = 2 -- To get Second Day of Business Month
OR MEC3 = 1 -- To get Last Day of Business Month
) THEN 1
ELSE 0
END AS [MEC_IND]
然后我选择 [MEC_IND] = 1
的日期 SELECT
Date_Value,
FIRST_DAY_OF_CALENDAR_MONTH_DATE
FROM ...
WHERE C.MEC_IND = 1
使用这种逻辑,我设法以这种方式获取日期,
我如何修改逻辑以将这些月末关闭业务日期分组到像这样的桶中
请记住,我使用的是 SQL Server 2008,无法使用 LEAD 和 LAG 功能。
有人可以指导我吗?任何帮助将不胜感激。提前致谢。
我能想到的最直接的方法是使用 dateadd()
和 case
表达式来根据 day()
添加一个或零个月并将结果截断到月初。
在此示例中使用临时日期 table:
declare @fromdate date = '20170428'
declare @thrudate date = '20170704'
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
, dates as (
select top (datediff(day, @fromdate, @thrudate)+1)
[Date]=convert(date,dateadd(day,row_number() over(order by (select 1))-1,@fromdate))
from n as deka cross join n as hecto cross join n as kilo
cross join n as tenK cross join n as hundredK
order by [Date]
)
select
date = [Date]
, EffectiveMonth = dateadd(month
, datediff(month, 0
, dateadd(month,case when day(date) > 27 then 1 else 0 end, [Date])
)
, 0)
from dates
where day(date) <4 or day(date) > 27; -- for brevity in results
rextester 演示:http://rextester.com/HJXXYL94271
returns:
+------------+----------------+
| date | EffectiveMonth |
+------------+----------------+
| 2017-04-28 | 2017-05-01 |
| 2017-04-29 | 2017-05-01 |
| 2017-04-30 | 2017-05-01 |
| 2017-05-01 | 2017-05-01 |
| 2017-05-02 | 2017-05-01 |
| 2017-05-03 | 2017-05-01 |
| 2017-05-28 | 2017-06-01 |
| 2017-05-29 | 2017-06-01 |
| 2017-05-30 | 2017-06-01 |
| 2017-05-31 | 2017-06-01 |
| 2017-06-01 | 2017-06-01 |
| 2017-06-02 | 2017-06-01 |
| 2017-06-03 | 2017-06-01 |
| 2017-06-28 | 2017-07-01 |
| 2017-06-29 | 2017-07-01 |
| 2017-06-30 | 2017-07-01 |
| 2017-07-01 | 2017-07-01 |
| 2017-07-02 | 2017-07-01 |
| 2017-07-03 | 2017-07-01 |
+------------+----------------+
要分解表达式,组合的主要两个部分是
dateadd()
,它使用 case
表达式来确定是否应添加月份(对于该月的最后一个工作日)(每月的第一个工作日)和日期截断。
带有case
表达式的dateadd()
是:
dateadd(month
, case when day(date) > 27 then 1 else 0 end
, [Date])
将日期截断到该月的第一天很简单,但语法可能不直观。将自
1900-01-01
以来的月数添加到日期 1900-01-01
可以让我们将日期截断到月初。
例如,对于当前日期:
select dateadd(month, datediff(month, 0, getdate() ), 0)
同一表达式的注释版本:
select dateadd(month
, datediff(month
, 0 /* '19000101' */
, getdate() /* date */
) /* end of datediff, returns integer number of months */
, 0 /* '19000101' */
)
将日期截断与我们用 case 表达式导出的日期组合起来,结果如下:
select dateadd(month
, datediff(month
, 0 /* '19000101' */
, dateadd(month
, case when day([Date]) > 27 then 1 else 0 end
, [Date]) /* date */
) /* end of datediff, returns integer number of months */
, 0 /* '19000101' */
)