在 SQL Server 2008 中从月份和年份创建日期
Posted
技术标签:
【中文标题】在 SQL Server 2008 中从月份和年份创建日期【英文标题】:Create Date From Month and Year in SQL Server 2008 【发布时间】:2017-11-27 20:29:41 【问题描述】:该表有月份和年份作为单独的列,我想创建一个函数,它将以DD-MM-YYYY
格式返回日期。
我需要为每个组合创建一个开始日期和结束日期,不幸的是架构无法更改,所以我可以使用它。
我已经粘贴了代码:
CREATE FUNCTION fn.GetDateFromMonthYear
(@isStartDate BIT,
@month INT,
@year INT)
RETURNS DATE
AS
BEGIN
DECLARE @finalDate AS DATE
IF (isStartDate)
BEGIN
SELECT @finalDate = CAST('01' + '-' + @month + @year AS DATE)
END
ELSE
BEGIN
SELECT @finalDate = CAST(CAST('01' + '-' + CAST(CAST(@month AS INT) + 1 AS VARCHAR(20)) + @year AS DATETIME) - 1 AS DATE
END
RETURN @startDate
END
有两件事这个功能的性能如何才能有任何改进。
我们如何处理闰年条件。
示例输入和输出
年 = 2017 月 = 11 isStartDate = true输出:2011 年 1 月 11 日
年= 2017 月 = 11 isStartDate = 假输出:30-11-2011
年= 2017 月 = 12 isStartDate = 假输出:2011 年 31 月 12 日
【问题讨论】:
为什么要将 int 月份转换为 int?请记住,您要在此处使用字符数据,而不是数字。所以添加月份和年份意味着你得到了加法,而不是字符串连接。您需要将这些转换为 varchar,然后将它们加在一起。正确的格式是 YYYYMMDD。任何其他格式,有时您会得到不正确的日期。 您要返回该月的第一天还是最后一天? @SeanLange 我想根据标志 isStartDate 返回第一个日期(01-11-2017)和最后一个日期(31-11-2017)。年份和月份在数据库中保存为 int,因此我正在尝试获取这些值。您能否更正并发布您认为最好的答案。对我来说,格式应该是 dd-mm-yyyy 【参考方案1】:我会使用内联表值函数而不是标量函数。它们更灵活,性能更好。此外,日期没有格式。该格式用于前端。 ANSI 批准的日期表示格式是 YYYYMMDD。无论您的本地设置是什么,这都会起作用。
这是一个使用内联表值函数执行此操作的完整示例。
create function GetDateFromMonthYear
(
@month int
, @year int
, @isStartDate bit
) returns table as return
select MyDate = case @isStartDate
when 1
then dateadd(month, datediff(month, 0, CONVERT(char(4), @year) + right('0' + CONVERT(varchar(2), @month), 2) + '01'), 0)
else dateadd(day, -1, dateadd(month, datediff(month, 0, CONVERT(char(4), @year) + right('0' + CONVERT(varchar(2), @month), 2) + '01') + 1, 0))
end
GO
declare @SomeDates table
(
MyYear int
, MyMonth int
, IsStartDate bit
)
insert @SomeDates
(
MyYear
, MyMonth
, IsStartDate
) values
(2017, 11, 1)
,(2017, 11, 0)
,(2017, 12, 1)
,(2017, 12, 0)
select *
from @SomeDates s
cross apply dbo.GetDateFromMonthYear(s.MyMonth, s.MyYear, s.isStartDate) x
【讨论】:
您的函数在检查不到 10 个月时会为我抛出错误。 @Alexey 对,你是……忘记了那些讨厌的个位数月份。没什么大不了的。现已修复。【参考方案2】:一个带日期的数学小技巧可以解决这个问题:
select dateadd(month, (YEARCOLUMN-1900)*12 + MONTHCOLUMN - ISSTARTDATE), ISSTARTDATE - 1)
日期在 SQLS 中以数字形式表示,0 表示 1900-01-01 00:00:00,每个整数增量为一天后
将您的年份减去 1900,然后乘以 12,得出我们必须 DATEADD 到开始日期 0(1900 年 1 月 1 日)才能到达您的年份的月数。
然后,如果它是开始日期,我们将比您的月份少一个(您的月份是 11,我们将 10 个月添加到一月以得到第 11 个月的开始),或者如果它是结束日期,我们添加月份 num (即我们再增加一个月,我们将在一天后使用另一个技巧回来)。
isstartdate 在开始日期时为 1,在结束日期时为 0,因此我们本质上添加 (monthnum - isstartdate) 来改变它是开始还是结束。请注意,目前该算法将为 2017、11 和 0 的组件生成 2017-12-01(即是结束日期),因此在这种情况下我们需要有一天回来,所以...
我们要做的唯一其他数学运算是从第 0 天开始计数,如果它是开始日期,则从 -1 开始计数,如果它是结束日期。这很容易通过从 isstartdate 中减去 1 来实现(这意味着当它是开始日期时我们从 0 开始计数,当它是结束日期时我们从 -1 开始计数。换句话说,当它是结束日期时,我们的月份被添加到 1899 -12-31)
http://www.sqlfiddle.com/#!6/9eecb7db59d16c80417c72d1e1f4fbf1/14236
注意:我已经使用“YEARCOLUMN”等占位符完成了这种 sql 样式;您只需将相关变量名替换为上述查询中的所有内容,即大写
【讨论】:
【参考方案3】:我知道您用“sql-server-2008”标记了您的问题,但是对于以后遇到此问题的任何人,SQL Server 2012 中添加了EOMONTH()
和DATEFROMPARTS()
函数。这两者都使您的问题成为更容易解决。
CREATE FUNCTION GetDateFromMonthYear
(
@month INT
, @year INT
, @isStartDate BIT
) RETURNS TABLE AS RETURN
SELECT MyDate = CASE @isStartDate
WHEN 1
THEN DATEFROMPARTS(@year, @month, 1)
ELSE EOMONTH(DATEFROMPARTS(@year, @month, 1))
END
【讨论】:
【参考方案4】:我会这样写,但想法基本相同:
create function dbo.GetDateFromMonthYear(
@isStartDate bit,
@month int,
@year int)
returns date
as
begin
return (
case when @isStartDate = 1
then convert(date, cast(@year as varchar(max)) + '-' + cast(@month as varchar(max)) + '-1', 121)
else dateadd(day, -1, dateadd(month, 1, convert(date, cast(@year as varchar(max)) + '-' + cast(@month as varchar(max)) + '-1', 121)))
end)
end
go
select
dbo.GetDateFromMonthYear(isStartDate, Month, Year)
from (values
(0, 2, 2016),
(0, 3, 2017),
(1, 4, 2017),
(1, 12, 2017)
)t(isStartDate, Month, Year)
【讨论】:
我仍然不建议在这里使用标量函数。它们对性能来说太痛苦了。【参考方案5】:这是一个使用 dateadd 的示例。如果该位为真,则取该月的第一天。如果该位为假,则加一个月减一天。
DECLARE @sample TABLE ([year] int, [month] int, isStartDate bit)
INSERT INTO @sample VALUES (2017, 11, 1), (2017, 11, 0), (2017, 12, 0)
SELECT CASE WHEN isStartDate = 1
THEN CONVERT(varchar, CAST(CAST(year as varchar) + CAST(month as varchar) + '01' as date), 105)
ELSE CONVERT(varchar, DATEADD(DAY, -1, DATEADD(MONTH, 1, CAST(CAST(year as varchar) + CAST(month as varchar) + '01' as date))), 105)
END
FROM @sample
生产:
01-11-2017
30-11-2017
31-12-2017
【讨论】:
以上是关于在 SQL Server 2008 中从月份和年份创建日期的主要内容,如果未能解决你的问题,请参考以下文章