这里有一个功能,让你计算它的飞行:
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年9月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列,否则,更新假日列1公司假期。注意:如果您实际上制作了上表,并且您对其的访问最经常使用与BusinessDate
不同的列上的JOIN或WHERE条件,则使主键非聚集并添加以备用列开始的聚集索引。
上述一些脚本需要SQL 2005或更高版本。
@marc_s再次感谢:)^5 –
你有没有签出[我的回答](http://stackoverflow.com/a/11320441/57611)? – ErikE