SQL 使用日历 table 确定自月初以来经过的工作日
SQL determine business days passed since beginning of month using calendar table
我有一个日历 table,其中包含所有日期和一个指示其是否为工作日的列。
例如
Date
Business_Day
1/1/2021
False
1/2/2021
False
1/3/2021
True
...
我还有另一个带日期的 table,想确定自该月初以来已经过去了多少个工作日。
例如:
Date
Business_Days_Passed
1/1/2022
0
1/2/2022
0
1/3/2022
1
1/4/2022
2
1/15/2022
10
2/2/2022
2
2/11/2022
9
2/12/2022
9
有没有办法使用标准 sql 来做到这一点?我正在考虑创建某种 UDF,但可能有更简单的方法吗?这使用雪花所以可以访问所有常见的日期函数和 window/udf 函数
这是一个简单的查询
Select count(c.date) from calendar c
Join dates_to_check d
Where month(c.date) = month(d.day)
And day(c.date) < day(d.day)
And business_Day = True;
我认为您可以使用简单的 join
和 window function
来完成此操作。我假设您的日期格式为 yyyy-mm-dd
,这将允许 left(date,7)
获得 year-month。如果没有,只需使用不同的函数来提取 year-month 以每月汇总。
select a.date,
count(b.business_day) over (partition by left(a.date,7) order by a.date) business_days_elapsed
from table a
left join calendar_table b on a.date=b.date and b.business_day='True'
group by a.date, b.business_day; --in case your data is not deduped before window function is applied
用单曲试试这个,table你可以创建一个视图
create or replace table bus_day as
SELECT column1 Date, column2 Business_Day from values
('1/1/2021', 'False'),
('1/2/2021', 'False'),
('1/3/2021', 'True'),
('1/4/2021', 'True'),
('1/5/2021', 'True'),
('1/6/2021', 'True'),
('1/7/2021', 'True'),
('2/1/2021', 'True'),
('2/2/2021', 'True'),
('2/3/2021', 'True'),
('2/4/2021', 'True'),
('2/5/2021', 'False'),
('2/6/2021', 'False'),
('2/7/2021', 'True')
;
SELECT DATE,FIRST_DAY_MONTH
,row_number() over (partition by month(to_date(Date,'mm/dd/yyyy')) order by date) as row_number
,count_if(business_day ='True') over (partition by month(to_date(Date,'mm/dd/yyyy')) order by DATE ) count_days
FROM (
select Date , DATE_TRUNC('month',to_date(Date,'mm/dd/yyyy')) frst_day,
iff(to_date(Date,'mm/dd/yyyy') = DATE_TRUNC('month',to_date(Date,'mm/dd/yyyy')), 'Y', 'N') first_day_Month ,
business_day from bus_day order by date
);
因此,如果您的 dates
有“所有日期”,您可以使用 JOIN
,例如:
SELECT d.date,
count_if(w.business_day) AS business_days_passed
FROM dates_of_interest AS d
JOIN work_days AS w
ON date_trunc(month, d.date) = date_trunc(month, w.date)
AND d.date >= w.date
GROUP BY 1
ORDER BY 1;
但是如果你的日期之间有间隔,就像我的示例数据一样......你会想要 LEFT JOIN 表单..
SELECT d.date,
count_if(w.business_day) AS business_days_passed
FROM dates_of_interest AS d
LEFT JOIN work_days AS w
ON date_trunc(month, d.date) = date_trunc(month, w.date)
AND d.date >= w.date
GROUP BY 1
ORDER BY 1;
并使用这个美妙的假数据:
WITH work_days(date, business_day) AS (
SELECT
DATEADD('day', ROW_NUMBER() OVER (ORDER BY NULL)-1, TO_DATE('1/1/2022', 'mm/dd/yyyy')) AS date
,DAYOFWEEKISO(date) < 6 AS business_day
FROM TABLE(generator(ROWCOUNT => 65))
), dates_of_interest(date) AS (
SELECT TO_DATE(column1, 'mm/dd/yyyy')
FROM VALUES
('1/1/2022'),
('1/2/2022'),
('1/3/2022'),
('1/4/2022'),
('1/15/2022'),
('2/2/2022'),
('2/11/2022'),
('2/12/2022')
)
我们得到:
DATE
BUSINESS_DAYS_PASSED
2022-01-01
0
2022-01-02
0
2022-01-03
1
2022-01-04
2
2022-01-15
10
2022-02-02
2
2022-02-11
9
2022-02-12
9
我有一个日历 table,其中包含所有日期和一个指示其是否为工作日的列。
例如
Date | Business_Day |
---|---|
1/1/2021 | False |
1/2/2021 | False |
1/3/2021 | True |
... 我还有另一个带日期的 table,想确定自该月初以来已经过去了多少个工作日。 例如:
Date | Business_Days_Passed |
---|---|
1/1/2022 | 0 |
1/2/2022 | 0 |
1/3/2022 | 1 |
1/4/2022 | 2 |
1/15/2022 | 10 |
2/2/2022 | 2 |
2/11/2022 | 9 |
2/12/2022 | 9 |
有没有办法使用标准 sql 来做到这一点?我正在考虑创建某种 UDF,但可能有更简单的方法吗?这使用雪花所以可以访问所有常见的日期函数和 window/udf 函数
这是一个简单的查询
Select count(c.date) from calendar c
Join dates_to_check d
Where month(c.date) = month(d.day)
And day(c.date) < day(d.day)
And business_Day = True;
我认为您可以使用简单的 join
和 window function
来完成此操作。我假设您的日期格式为 yyyy-mm-dd
,这将允许 left(date,7)
获得 year-month。如果没有,只需使用不同的函数来提取 year-month 以每月汇总。
select a.date,
count(b.business_day) over (partition by left(a.date,7) order by a.date) business_days_elapsed
from table a
left join calendar_table b on a.date=b.date and b.business_day='True'
group by a.date, b.business_day; --in case your data is not deduped before window function is applied
用单曲试试这个,table你可以创建一个视图
create or replace table bus_day as
SELECT column1 Date, column2 Business_Day from values
('1/1/2021', 'False'),
('1/2/2021', 'False'),
('1/3/2021', 'True'),
('1/4/2021', 'True'),
('1/5/2021', 'True'),
('1/6/2021', 'True'),
('1/7/2021', 'True'),
('2/1/2021', 'True'),
('2/2/2021', 'True'),
('2/3/2021', 'True'),
('2/4/2021', 'True'),
('2/5/2021', 'False'),
('2/6/2021', 'False'),
('2/7/2021', 'True')
;
SELECT DATE,FIRST_DAY_MONTH
,row_number() over (partition by month(to_date(Date,'mm/dd/yyyy')) order by date) as row_number
,count_if(business_day ='True') over (partition by month(to_date(Date,'mm/dd/yyyy')) order by DATE ) count_days
FROM (
select Date , DATE_TRUNC('month',to_date(Date,'mm/dd/yyyy')) frst_day,
iff(to_date(Date,'mm/dd/yyyy') = DATE_TRUNC('month',to_date(Date,'mm/dd/yyyy')), 'Y', 'N') first_day_Month ,
business_day from bus_day order by date
);
因此,如果您的 dates
有“所有日期”,您可以使用 JOIN
,例如:
SELECT d.date,
count_if(w.business_day) AS business_days_passed
FROM dates_of_interest AS d
JOIN work_days AS w
ON date_trunc(month, d.date) = date_trunc(month, w.date)
AND d.date >= w.date
GROUP BY 1
ORDER BY 1;
但是如果你的日期之间有间隔,就像我的示例数据一样......你会想要 LEFT JOIN 表单..
SELECT d.date,
count_if(w.business_day) AS business_days_passed
FROM dates_of_interest AS d
LEFT JOIN work_days AS w
ON date_trunc(month, d.date) = date_trunc(month, w.date)
AND d.date >= w.date
GROUP BY 1
ORDER BY 1;
并使用这个美妙的假数据:
WITH work_days(date, business_day) AS (
SELECT
DATEADD('day', ROW_NUMBER() OVER (ORDER BY NULL)-1, TO_DATE('1/1/2022', 'mm/dd/yyyy')) AS date
,DAYOFWEEKISO(date) < 6 AS business_day
FROM TABLE(generator(ROWCOUNT => 65))
), dates_of_interest(date) AS (
SELECT TO_DATE(column1, 'mm/dd/yyyy')
FROM VALUES
('1/1/2022'),
('1/2/2022'),
('1/3/2022'),
('1/4/2022'),
('1/15/2022'),
('2/2/2022'),
('2/11/2022'),
('2/12/2022')
)
我们得到:
DATE | BUSINESS_DAYS_PASSED |
---|---|
2022-01-01 | 0 |
2022-01-02 | 0 |
2022-01-03 | 1 |
2022-01-04 | 2 |
2022-01-15 | 10 |
2022-02-02 | 2 |
2022-02-11 | 9 |
2022-02-12 | 9 |