Fet*_*Fet 2 sql t-sql sql-server date-arithmetic
我如何将一年周(例如0852或200852)转换为日期(例如2008-12-31或特别是周末结束日,即2008-12-27周六或周开始日,即2008-12-21 )?星期五,星期六,星期日或星期一,星期结束的任何一天都会.
MS SQL SERVER有DATEADD功能,应该有帮助......
DECLARE @date_string NCHAR(6)
SELECT @date_string = N'200852'
SELECT DATEADD(
WEEK,
CAST(RIGHT(@date_string, 2) AS INT),
DATEADD(
YEAR,
CAST(LEFT(@date_string, 4) AS INT) - 1900,
0
)
)
Run Code Online (Sandbox Code Playgroud)
编辑:
对不起,错过了关于星期六等等的一点......
获得该值后,使用DATEPART获取一周中的哪一天,并从您的答案中减去...
DECLARE @new_date DATETIME
SELECT @new_date = '2008 Dec 30'
SELECT DATEADD(DAY, 1-DATEPART(dw, @new_date), @new_date)
Run Code Online (Sandbox Code Playgroud)
这会将值带到一周的开始,具体取决于您将DATEFIRST设置为的值.
如果这很重要的话,这是一个几乎独立于数据库的解决方案。
创建一个名为 ALMANAC、主键 DATE 的表,其中列出了您计划使用的日期的所有属性。其中一个可能是“年”,另一个可能是“周”。您可以包含您想要经常使用的 DATE 的任何可计算函数。您还可以包含公司特定的 DATE 属性,例如该日期是否是公司假期。
编写一个程序来填充 DATE 10 年(大约 3650 行加上一些闰年)。该程序将使用 DBMS 或某种编程语言中可用的环境特定日期函数。一旦填充了 ALMANAC 表,就可以像普通数据一样使用它。将主键与数据库中的任何日期字段连接起来。
事实证明,这对于几乎自动地按周、按月、按季度和按年准备报告等事情非常有用。
如果 DATE 的粒度不够细,您甚至可以将年历划分为更小的时间单位,例如轮班,其中 3 个班次为一天。
我为此目的创建了一个UDF 。它将 YYYYWW 字符串或数字转换为日期。
CREATE FUNCTION dbo.GetDateFromYearWeek (
@YearWeek VARCHAR(7) = '000101', -- default
@WeekDay INT = 1, -- default
@FirstWeekDayName VARCHAR(9) = 'mon' -- default
) RETURNS DATE
BEGIN
IF @YearWeek = '000101'
SET @YearWeek = CONCAT(DATEPART(year, GETDATE()), '-', DATEPART(week, GETDATE()));
IF @YearWeek NOT LIKE '[0-9][0-9][0-9][0-9]%[0-9-][0-9]'
RETURN NULL;
IF @WeekDay < 1 OR @WeekDay > 7
RETURN NULL;
DECLARE @FirstWeekDay INT = CHARINDEX(LOWER(LEFT(@FirstWeekDayName,3)), ' montuewedthufrisatsun')/3;
IF @FirstWeekDay = 0 -- not found in string
SET @FirstWeekDay = @@DATEFIRST;
DECLARE @Year INT = TRY_CAST(LEFT(@YearWeek, 4) AS INT);
DECLARE @Week INT = ABS(TRY_CAST(RIGHT(@YearWeek, 2) AS INT));
DECLARE @Date DATE = TRY_CAST(CONCAT(@Year,'-01-01') AS DATE);
SET @Date = DATEADD(week, @Week-1, @Date);
DECLARE @DowDiff INT = (6-@FirstWeekday+@@DATEFIRST+DATEPART(weekday,@Date))%7;
SET @Date = DATEADD(day, -@DowDiff, @Date);
SET @Date = DATEADD(day, @WeekDay-1, @Date);
RETURN @Date;
END;
Run Code Online (Sandbox Code Playgroud)
用法示例:
SELECT *
, [StartOfWeek_SundayFirst] = dbo.GetDateFromYearWeek(col, 1, 'sun')
, [StartOfWeek_MondayFirst] = dbo.GetDateFromYearWeek(col, 1, 'mon')
, [EndOfWeek_SundayFirst] = dbo.GetDateFromYearWeek(col, 7, 'sunday')
, [EndOfWeek_MondayFirst] = dbo.GetDateFromYearWeek(col, 7, 'monday')
FROM (VALUES (202201), (202202)) q(col)
ORDER BY 1;
Run Code Online (Sandbox Code Playgroud)
坳 | StartOfWeek_SundayFirst | StartOfWeek_MondayFirst | EndOfWeek_SundayFirst | EndOfWeek_MondayFirst |
---|---|---|---|---|
202201 | 2021-12-26 | 2021-12-27 | 2022-01-01 | 2022-01-02 |
202202 | 2022-01-02 | 2022-01-03 | 2022-01-08 | 2022-01-09 |
在db<>fiddle上测试它。
ISO_WEEK 版本
Run Code Online (Sandbox Code Playgroud)CREATE FUNCTION dbo.GetDateFromIsoYearWeek ( @YearWeek VARCHAR(7) = '0000-00', -- default @WeekDay INT = 1 -- default ) RETURNS DATE BEGIN IF @YearWeek = '0000-00' SET @YearWeek = CONCAT(DATEPART(year, GETDATE()), '-', DATEPART(iso_week, GETDATE())); IF @YearWeek NOT LIKE '[0-9][0-9][0-9][0-9]%[0-9-][0-9]' RETURN NULL; IF @WeekDay < 1 OR @WeekDay > 7 RETURN NULL; DECLARE @FirstWeekDay INT = 1; -- monday DECLARE @Year INT = TRY_CAST(LEFT(@YearWeek, 4) AS INT); DECLARE @Week INT = ABS(TRY_CAST(RIGHT(@YearWeek, 2) AS INT)); DECLARE @Date DATE = TRY_CAST(CONCAT(@Year,'-01-08') AS DATE); SET @Date = DATEADD(week, @Week - 2 + (DATEPART(week, @Date)-(DATEPART(iso_week, @Date))), @Date); DECLARE @DowDiff INT = (6-@FirstWeekday+@@DATEFIRST+DATEPART(weekday,@Date))%7; SET @Date = DATEADD(day, -@DowDiff, @Date); SET @Date = DATEADD(day, @WeekDay-1, @Date); RETURN @Date; END;
Run Code Online (Sandbox Code Playgroud)DECLARE @Test TABLE ([column] char(7)); INSERT INTO @Test VALUES ('2020-53'), ('2021-01'), ('2021-02') , ('2021-48') , ('2021-53'), ('2022-01'), ('2022-02') ; SELECT [column] , [FirstOfWeek] = dbo.GetDateFromIsoYearWeek([column], 1) , [LastOfWeek] = dbo.GetDateFromIsoYearWeek([column], 7) FROM @Test ORDER BY 1;
柱子 第一周 最后一周 2020-53 2020-12-28 2021-01-03 2021-01 2021-01-04 2021-01-10 2021年02月 2021-01-11 2021-01-17 2021-48 2021-11-29 2021-12-05 2021-53 2022-01-03 2022-01-09 2022年01月 2022-01-03 2022-01-09 2022年02月 2022-01-10 2022-01-16
在db<>fiddle上测试它。