这是一个供您即时计算的函数:
CREATE FUNCTION dbo.WholeWeekFromDate (
@Date datetime
)
RETURNS tinyint
AS BEGIN
RETURN (
SELECT DateDiff(Day, DateAdd(Year, DateDiff(Year, 0, CalcDate), 0), CalcDate) / 7 + 1
FROM (SELECT DateAdd(Day, (DateDiff(Day, 0, @Date) + 1) / 7 * 7, 0)) X (CalcDate)
);
END;
我不建议您使用它,因为它可能会因为每行调用一次而表现不佳。如果您绝对必须有一个函数才能在实际查询中使用,则将其转换为返回单个列和行的内联函数,并按如下方式使用它:
SELECT
OtherColumns,
(SELECT WeekNumber FROM dbo.WholeWeekFromDate(DateColumn)) WeekNumber
FROM
YourTable;
这将允许它在执行计划中“内联”并执行得更好。
但正如其他人所建议的那样,更好的是使用 BusinessDate 表。这是为您创建一个的先机:
CREATE TABLE dbo.BusinessDate (
BusinessDate date NOT NULL CONSTRAINT PK_BusinessDate PRIMARY KEY CLUSTERED,
WholeWeekYear smallint NOT NULL
CONSTRAINT CK_BusinessDate_WholeWeekYear_Valid
CHECK (WholeWeekYear BETWEEN 1900 AND 9999),
WholeWeekNumber tinyint NOT NULL
CONSTRAINT CK_BusinessDate_WholeWeekNumber_Valid
CHECK (WholeWeekNumber BETWEEN 1 AND 53),
Holiday bit CONSTRAINT DF_BusinessDate_Holiday DEFAULT (0),
Weekend bit CONSTRAINT DF_BusinessDate_Weekend DEFAULT (0),
BusinessDay AS
(Convert(bit, CASE WHEN Holiday = 0 AND Weekend = 0 THEN 1 ELSE 0 END)) PERSISTED
);
我什至会从 1900-01-01 到 2617-09-22 填充它(这足以满足您产品的预计寿命吗?它只有 7.8MB,所以不要担心过大):
WITH A (N) AS (SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1),
B (N) AS (SELECT 1 FROM A F, A A, A L, A C, A O, A N),
C (N) AS (SELECT Row_Number() OVER (ORDER BY (SELECT 1)) FROM B),
Dates AS (
SELECT
N,
DateAdd(Day, N, '18991231') Dte,
DateAdd(Day, N / 7 * 7, '19000101') CalcDate
FROM C
)
INSERT dbo.BusinessDate
SELECT
Dte,
Year(CalcDate),
DateDiff(Day, DateAdd(Year, DateDiff(Year, 0, CalcDate), 0), CalcDate) / 7 + 1,
0,
(N + 6) % 7 / 5 -- calculate weekends
FROM Dates; -- 3-7 seconds or so on my VM server
然后在日期加入表,并使用 WholeWeekNumber 列作为输出。您也可以考虑添加一个 WeekNumberYear,因为如果没有这个,很难确定 2009-01-01 的 52 确实属于 2008 ......如果你不这样做,肯定会有一个奇怪的数据点(笑)。
示例表内容:
BusinessDate WholeWeekYear WholeWeekNumber Holiday Weekend BusinessDay
------------ ------------- --------------- ------- ------- -----------
1/1/2009 2008 52 0 0 1
1/2/2009 2008 52 0 0 1
1/3/2009 2008 52 0 1 0
1/4/2009 2009 1 0 1 0
1/5/2009 2009 1 0 0 1
1/6/2009 2009 1 0 0 1
1/7/2009 2009 1 0 0 1
1/8/2009 2009 1 0 0 1
1/9/2009 2009 1 0 0 1
1/10/2009 2009 1 0 1 0
1/11/2009 2009 2 0 1 0
如果您真的不想将其用作一般的营业日期计算表,您可以删除最后 3 列,否则,将公司假期的 Holiday 列更新为 1。
注意:如果您确实制作了上面的表,并且您对它的访问通常在不同的列上使用 JOIN 或 WHERE 条件BusinessDate
,则将主键设为非聚集的并添加从备用列开始的聚集索引。
上述某些脚本需要 SQL 2005 或更高版本。