确定性标量函数,以获取日期的星期几
-
05-07-2019 - |
题
SQL Server,尝试通过确定性UDF获取星期几。
我确信这一定是可能的,但无法弄明白。
更新:示例代码..
CREATE VIEW V_Stuff WITH SCHEMABINDING AS
SELECT
MD.ID,
MD.[DateTime]
...
dbo.FN_DayNumeric_DateTime(MD.DateTime) AS [Day],
dbo.FN_TimeNumeric_DateTime(MD.DateTime) AS [Time],
...
FROM {SOMEWHERE}
GO
CREATE UNIQUE CLUSTERED INDEX V_Stuff_Index ON V_Stuff (ID, [DateTime])
GO
解决方案
好的,我认为..
CREATE FUNCTION [dbo].[FN_DayNumeric_DateTime]
(@DT DateTime)
RETURNS INT WITH SCHEMABINDING
AS
BEGIN
DECLARE @Result int
DECLARE @FIRST_DATE DATETIME
SELECT @FIRST_DATE = convert(DATETIME,-53690+((7+5)%7),112)
SET @Result = datediff(dd,dateadd(dd,(datediff(dd,@FIRST_DATE,@DT)/7)*7,@FIRST_DATE), @DT)
RETURN (@Result)
END
GO
其他提示
与上述解决方案略有相似的方法,但只是一个可以在函数内部使用的单行程序或计算列的内联。
假设:
- 您之前没有日期 1899-12-31(周日)
- 你想模仿@@ datefirst = 7
- @dt是smalldatetime,datetime, date或datetime2数据类型 醇>
如果您想要与众不同,请将日期'18991231'更改为您希望等于1的工作日的日期.convert()函数是使整个工作正常工作的关键 - 强制转换不是诀窍:
((datediff(day,convert(datetime, '18991231',112),@ dt)%7) + 1)
;
with
Dates(DateValue) as
(
select cast('2000-01-01' as date)
union all
select dateadd(day, 1, DateValue) from Dates where DateValue < '2050-01-01'
)
select
year(DateValue) * 10000 + month(DateValue) * 100 + day(DateValue) as DateKey, DateValue,
datediff(day, dateadd(week, datediff(week, 0, DateValue), 0), DateValue) + 2 as DayOfWeek,
datediff(week, dateadd(month, datediff(month, 0, DateValue), 0), DateValue) + 1 as WeekOfMonth,
datediff(week, dateadd(year, datediff(year, 0, DateValue), 0), DateValue) + 1 as WeekOfYear
from Dates option (maxrecursion 0)
我知道这篇文章已经超级老了,但是我试图做一个类似的事情,并提出了一个不同的解决方案,并认为我会发布后代。另外,我做了一些搜索,并没有找到关于这个问题的更多内容。
就我而言,我试图使用计算列PERSISTED,这要求计算是确定性的。我使用的计算是:
datediff(dd,'2010-01-03',[DateColumn]) % 7 + 1
我们的想法是找出一个已知的星期日,你知道会在你的表格中任何可能的日期之前发生(在这种情况下,2010年1月3日),然后计算自该星期日以来天数的模数7 + 1。
问题是在函数调用中包含一个文字日期足以将其标记为非确定性。您可以通过使用整数0来表示时间段来解决这个问题,对于SQL Server,它是1900年1月1日的星期日。
datediff(dd,0,[DateColumn]) % 7 + 1
当datefirst设置为7(默认为美国)时,+1只会使结果与datepart(dw,[datecolumn])相同,它将星期日设置为1,将星期一设置为2,等等
我也可以结合案例[thatComputedColumn]当1然后'星期日'时2然后'星期一'......等等,但是确定性的,这是我周围的要求。
在sql中有一个已经内置的函数来执行它:
SELECT DATEPART(weekday, '2009-11-11')
修改强>: 如果你真的需要确定性UDF:
CREATE FUNCTION DayOfWeek(@myDate DATETIME )
RETURNS int
AS
BEGIN
RETURN DATEPART(weekday, @myDate)
END
GO
SELECT dbo.DayOfWeek('2009-11-11')
再次编辑:这实际上是错误的,因为 DATEPART(工作日)
不是确定性的。
<强>更新强>:
DATEPART(工作日)
是非确定性的,因为它依赖于 DATEFIRST
( source )。
您可以使用 SET DATEFIRST
更改它,但不能在存储的函数内调用它。
我认为下一步是使用您首选的DATEFIRST 制作您自己的实施它(并没有考虑它,例如使用 Monday 作为第一天)。
建议的解决方案有一个问题 - 它在周六返回0。假设我们正在寻找与 DATEPART(WEEKDAY)
兼容的东西,这是一个问题。
但是,没有什么简单的 CASE
语句不会修复。
创建一个函数,并将@dbdate varchar(8)作为输入变量。
让它返回以下内容:
RETURN (DATEDIFF(dd, -1, convert(datetime, @dbdate, 112)) % 7)+1;
值112是sql样式YYYYMMDD。
这是确定性的,因为datediff没有收到字符串输入,如果它要接收一个它不再有效的字符串,因为它在内部将它转换为datetime对象。这不是确定性的。
不确定您要找的是什么,但如果这是网站的一部分,请从 http://php.net/manual/en/function.date.php
function weekday($fyear, $fmonth, $fday) //0 is monday
{
return (((mktime ( 0, 0, 0, $fmonth, $fday, $fyear) - mktime ( 0, 0, 0, 7, 17, 2006))/(60*60*24))+700000) % 7;
}
星期几?你为什么不只使用DATEPART?
DATEPART(weekday, YEAR_DATE)
你不能只用以下的东西选择它:
SELECT DATENAME(dw, GETDATE());