确定性标量函数,以获取日期的星期几

时间:2009-11-26 13:04:49

标签: sql-server user-defined-functions

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

11 个答案:

答案 0 :(得分:6)

好的,我认为..

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

答案 1 :(得分:6)

与上述解决方案略有相似的方法,但只是一个可以在函数内部使用的单行程序或计算列的内联。

假设:

  1. 您之前没有日期 1899-12-31(周日)
  2. 你想模仿@@ datefirst = 7
  3. @dt是smalldatetime,datetime, date或datetime2数据类型
  4. 如果您想要与众不同,请将日期'18991231'更改为您希望等于1的工作日的日期.convert()函数是使整个工作正常工作的关键 - 强制转换不是诀窍:

      

    ((datediff(day,convert(datetime,   '18991231',112),@ dt)%7)   + 1)

答案 2 :(得分:1)

取自Deterministic scalar function to get week of year for a date

;
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)

答案 3 :(得分:1)

我知道这篇文章已经超级老了,但是我试图做一个类似的事情,想出了一个不同的解决方案,并认为我会为后代发帖。另外,我做了一些搜索,并没有找到关于这个问题的更多内容。

就我而言,我试图使用计算列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然后'星期一'......等等,但是确定性的,这是我周围的要求。

答案 4 :(得分:0)

在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(weekday)不是确定性的。

<强>更新DATEPART(weekday)是非确定性的,因为它依赖于DATEFIRSTsource) 您可以使用SET DATEFIRST更改它,但不能在存储的函数内调用它。

我认为下一步是make your own implementation,在其中使用您首选的DATEFIRST(根本不考虑它,例如使用 Monday 作为第一天)。

答案 5 :(得分:0)

建议的解决方案有一个问题 - 它在周六返回0。假设我们正在寻找与DATEPART(WEEKDAY)兼容的内容,这是一个问题。

不过,简单的CASE语句不会修复。

答案 6 :(得分:0)

创建一个函数,并将@dbdate varchar(8)作为输入变量。

让它返回以下内容:

RETURN (DATEDIFF(dd, -1, convert(datetime, @dbdate, 112)) % 7)+1;

值112是sql样式YYYYMMDD。

这是确定性的,因为datediff不接收字符串输入,如果要接收字符串,它将不再起作用,因为它内部将其转换为datetime对象。不确定的。

答案 7 :(得分:0)

尽管这很旧。评论简单的答案以帮助将来的读者。 @ liver-larson几乎是正确的。错误地将纪元时间0(1900年1月1日)设为星期日。实际上是星期一。

代码错误-https://stackoverflow.com/a/20481717/2012977

datediff(dd,0,[DateColumn]) % 7 + 1

更正

datediff(dd,-1,[DateColumn]) % 7 + 1

我喜欢这个答案,因为没有日期转换发生并且可以确定。

代码的单元测试。不幸的是,在撰写本文时SqlFiddle下降了。注意此处对列值进行硬编码。期望列为日期类型。

SELECT DATEPART(WEEKDAY, '2020-06-14'), DATEDIFF(dd, -1, '2020-06-14') % 7 + 1
SELECT DATEPART(WEEKDAY, '2020-06-15'), DATEDIFF(dd, -1, '2020-06-15') % 7 + 1
SELECT DATEPART(WEEKDAY, '2020-06-16'), DATEDIFF(dd, -1, '2020-06-16') % 7 + 1
SELECT DATEPART(WEEKDAY, '2020-06-17'), DATEDIFF(dd, -1, '2020-06-17') % 7 + 1
SELECT DATEPART(WEEKDAY, '2020-06-18'), DATEDIFF(dd, -1, '2020-06-18') % 7 + 1
SELECT DATEPART(WEEKDAY, '2020-06-19'), DATEDIFF(dd, -1, '2020-06-19') % 7 + 1
SELECT DATEPART(WEEKDAY, '2020-06-20'), DATEDIFF(dd, -1, '2020-06-20') % 7 + 1

答案 8 :(得分:-1)

不确定您要找的是什么,但如果这是网站的一部分,请从http://php.net/manual/en/function.date.php

尝试此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;
}

答案 9 :(得分:-1)

星期几?你为什么不只使用DATEPART?

DATEPART(weekday, YEAR_DATE)

答案 10 :(得分:-1)

你不能只用以下的东西选择它:

SELECT DATENAME(dw, GETDATE());