![](/img/trans.png)
[英]How could I get the the date of the week, month or year starting from the first day up to the current day of the current week, month or year?
[英]SQL: get first day of the current year week based
許多人建議如何獲取當前年份的第一個日期(基於月份),例如:
SELECT DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), 0)
這將導致:
2021-01-01 00:00:00.000
應該是 2021-01-04。 (第一周的星期一(美國的星期日))
我需要的是類似的但基於周的。 例如,第一周可能從 12 月 31 日開始,因此該函數應該返回 12 月 31 日,而不是 1 月 1 日。
有任何想法嗎 ?
為此,使用內聯表值函數比使用標量函數要好得多(這里有一些詳細信息)。
我根據上面評論中顯示的所需結果創建了一個為任何給定日期生成年份的第一個星期一。 如果您想要周日的東西,請在您的問題中提供示例數據/所需的結果:
CREATE FUNCTION dbo.GetFirstMonday
(
@date date
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
WITH km(km) AS (SELECT CONVERT(date, '20180101')), -- known Monday
d AS (SELECT FirstOfYear = DATEFROMPARTS(YEAR(@date),1,1)),
w AS (SELECT FirstMonday = DATEADD(WEEK, DATEDIFF(WEEK, km, FirstOfYear)
+ CASE WHEN ((@@DATEFIRST + DATEPART(WEEKDAY, FirstOfYear))) IN (6,13)
THEN 1 ELSE 0 END, km) FROM d CROSS JOIN km)
SELECT FirstMonday FROM w
);
用法:
SET DATEFIRST 5;
DECLARE @src TABLE(InputDate date);
INSERT @src(InputDate) VALUES
('20160608'),('20170505'),('20180405'),
('20190303'),('20200903'),('20210706');
SELECT * FROM @src AS src
CROSS APPLY dbo.GetFirstMonday(src.InputDate);
結果(對於任何DATEFIRST
設置):
InputDate FirstMonday
---------- -----------
2016-06-08 2016-01-04
2017-05-05 2017-01-02
2018-04-05 2018-01-01
2019-03-03 2018-12-31
2020-09-03 2019-12-30
2021-07-06 2021-01-04
另一種思考方式是:如果一年的第一個星期一與一年的第一天相距超過2天(例如一年開始於 ,則取一年的第一天之前的第一個星期一,可以在最多 3 天前。因此,此函數從{first of year} - {3 days}
=> {first of year} + {3 days}
- 其中一天的 7 天范圍中獲取匹配工作日的MIN()
必須是您所追求的星期一(如果您的規則不是三天,則很容易改變):
CREATE FUNCTION dbo.GetFirstWeekday
(
@date date,
@DayName char(6)
)
RETURNS TABLE WITH SCHEMABINDING
AS
RETURN (WITH n(n) AS (SELECT -3 UNION ALL SELECT n+1 FROM n WHERE n < 3),
d(d) AS (SELECT DATEADD(DAY, n, DATEFROMPARTS(YEAR(@date),1,1)) FROM n)
SELECT DayName = @DayName, FirstWeekday = MIN(d) FROM d
WHERE DATENAME(WEEKDAY, d) = @DayName
);
所以給出:
DECLARE @src TABLE(InputDate date);
INSERT @src(InputDate) VALUES
('20160108'),('20170505'),('20180405'),
('20190303'),('20200403'),('20210506');
SELECT * FROM @src AS src
CROSS APPLY dbo.GetFirstWeekday(src.InputDate, 'Monday');
結果:
InputDate FirstWeekday
---------- ------------
2016-06-08 2016-01-04
2017-05-05 2017-01-02
2018-04-05 2018-01-01
2019-03-03 2018-12-31
2020-09-03 2019-12-30
2021-07-06 2021-01-04
這也與@@DATEFIRST
沒有任何關系,但它確實依賴於@@LANGUAGE
在英語領域。
但實際上,如果幾年中的每一年都只有一個星期日或星期一,而您已經知道規則,為什么不創建一個表,定義一次這些規則,而不是提出古怪且明顯靈活的語法呢?
CREATE TABLE dbo.FirstSundayMondayRules
(
TheYear int PRIMARY KEY,
FirstSunday date NOT NULL,
FirstMonday date NOT NULL
);
-- guessing at your Sunday rules here
INSERT dbo.FirstSundayMondayRules VALUES
(2016, '20160103', '20160104'),
(2019, '20181230', '20181231');
現在您可以創建一個更簡單的函數:
CREATE FUNCTION dbo.GetFirstWeekday
(
@Date date,
@DayName char(6)
)
RETURNS TABLE WITH SCHEMABINDING
AS
RETURN (SELECT FirstWeekday = CASE @DayName
WHEN 'Sunday' THEN FirstSunday
WHEN 'Monday' THEN FirstMonday END
FROM dbo.FirstSundayMondayRules
WHERE TheYear = DATEPART(YEAR, @Date)
);
並且DATEFIRST
不再具有任何相關性,至少作為任何計算的一部分:
SET DATEFIRST 5;
DECLARE @src TABLE(InputDate date);
INSERT @src(InputDate) VALUES
('20160608'),('20190303');
SELECT 'Sunday', * FROM @src AS src
CROSS APPLY dbo.GetFirstWeekday(src.InputDate, 'Sunday');
SELECT 'Monday', * FROM @src AS src
CROSS APPLY dbo.GetFirstWeekday(src.InputDate, 'Monday');
結果:
(No column name) InputDate FirstWeekday
---------------- ---------- ------------
Sunday 2016-06-08 2016-01-03
Sunday 2019-03-03 2018-12-30
(No column name) InputDate FirstWeekday
---------------- ---------- ------------
Monday 2016-06-08 2016-01-04
Monday 2019-03-03 2018-12-31
或者更好的是,給自己一個Calendar 表,你可以只在列中硬編碼FirstSundayOfYear
和FirstMondayOfYear
。
所以我想出了一個解決方案,但可能有一個更優雅的解決方案
-- =============================================
-- Author: PLANSIS
-- Create date: 2020-11-25
-- Description: first day of the current year week based (monday of the first week)
-- =============================================
CREATE OR ALTER FUNCTION [dbo].[A_FN_TI_FirstDayCurrentYearWeek]
(
@date date = null
)
RETURNS datetime
AS
BEGIN
set @date = coalesce( @date , getdate() )
DECLARE @ResultVar datetime
DECLARE @wk int
DECLARE @yr int
SET @yr = year(@date)
SET @wk = 1
SELECT @ResultVar = dateadd (week, @wk, dateadd (year, @yr-1900, 0)) - 4 -
datepart(dw, dateadd (week, @wk, dateadd (year, @yr-1900, 0)) - 4) + 2 -- +2 for europe, +1 for US
-- Return the result of the function
RETURN @ResultVar
END
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.