SQL Server - 把星期一(周一)当作每个星期的开始在一年中求取周数
先感叹一句!好长时间没有更新博客了!偶尔看到一句话,觉得被电击了 - 庸人败于懒,能人败于傲!

-- The default first date in a week is Sunday, the value is 7
SELECT @@DATEFIRST -- Default DATEFIRST is Sunday
SELECT DATENAME(WEEK,'2013-12-31') AS WeekName --
SELECT DATENAME(WEEK,'2014-01-01') AS WeekName --
SELECT DATENAME(WEEK,'2014-01-05') AS WeekName -- -- Change the DATEFIRST to 1, Monday will be the first day of week.
SET DATEFIRST 1 SELECT @@DATEFIRST -- -- After change the DATEFIRST to Monday
SELECT DATENAME(WEEK,'2013-12-31') AS WeekName --
SELECT DATENAME(WEEK,'2014-01-01') AS WeekName --
SELECT DATENAME(WEEK,'2014-01-05') AS WeekName --
要注意的是 SET DATEFIRST 只在当前执行中有效,也就说比如新开一个查询页面继续查询 SELECT @@DATEFIRST 则还是显示默认值 7。
在创建时间维度的代码中添加 SET DATEFIRST 1,表示每周以周一开始。
USE BIWORK_SSIS
GO
SET NOCOUNT ON -- 设置每周的起始天为周一
SET DATEFIRST 1 IF OBJECT_ID('DimDateStartWithMonday','U') IS NOT NULL
DROP TABLE DimDateStartWithMonday
GO CREATE TABLE DimDateStartWithMonday
(
DateKey INT PRIMARY KEY,
FullDate DATE NOT NULL,
[DateName] NVARCHAR(20),
DayNumberOfWeek TINYINT NOT NULL,
DayNameOfWeek NVARCHAR(10) NOT NULL,
DayNumberOfMonth TINYINT NOT NULL,
DayNumberOfYear SMALLINT NOT NULL,
WeekNumberOfYear TINYINT NOT NULL,
EnglishMonthName NVARCHAR(10) NOT NULL,
MonthNumberOfYear TINYINT NOT NULL,
CalendarQuarter TINYINT NOT NULL,
CalendarSemester TINYINT NOT NULL,
CalendarYear SMALLINT NOT NULL
) DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME SELECT @StartDate = '2001-01-01',
@EndDate = '2035-12-31' WHILE (@StartDate <= @EndDate)
BEGIN
INSERT INTO DimDateStartWithMonday
(
DateKey,
FullDate,
[DateName],
DayNumberOfWeek,
DayNameOfWeek,
DayNumberOfMonth,
DayNumberOfYear,
WeekNumberOfYear,
EnglishMonthName,
MonthNumberOfYear,
CalendarQuarter,
CalendarSemester,
CalendarYear
)
SELECT CAST(CONVERT(VARCHAR(8),@StartDate,112) AS INT) AS DateKey,
CONVERT(VARCHAR(10), @StartDate,20) AS FullDate,
CONVERT(VARCHAR(20), @StartDate,106) AS [DateName],
DATEPART(DW,@StartDate) AS DayNumberOfWeek,
DATENAME(DW,@StartDate) AS DayNameOfWeek,
DATENAME(DD,@StartDate) AS [DayOfMonth],
DATENAME(DY,@StartDate) AS [DayOfYear],
DATEPART(WW,@StartDate) AS WeekNumberOfYear,
DATENAME(MM,@StartDate) AS EnglishMonthName,
DATEPART(MM,@StartDate) AS MonthNumberOfYear,
DATEPART(QQ,@StartDate) AS CalendarQuarter,
CASE WHEN DATEPART(MM,@StartDate) BETWEEN 1 AND 6
THEN 1
ELSE 2
END AS CalendarSemester,
DATEPART(YY,@StartDate) AS CalendarYear SET @StartDate = @StartDate + 1
END
GO
最后是函数,这个函数麻烦的地方就是要考虑周日的情况。默认情况下,周日是每个星期的第一天,但是这里改成了周一是每周的第一天,逻辑上就会复杂很多。
比如,2012-01-01 是周日,2012-01-02 是周一。按默认情况,这两天的 Week Number 都是 1,但是这里需要把 2012-01-02 的 Week Number 变成 2。
比如,2011-01-01 是周六,2012-01-02 是周日。按默认情况,周六的 Week Number 是 1, 周日的是 2。但是这里需要把周六和周日的都变成 1, 周一的变成 2。
除此之外,还要考虑之后的每一个周日与周一的交替情况。
USE BIWORK_SSIS
GO IF OBJECT_ID('ETLWORK_GETWEEKNUMBER','FN') IS NOT NULL
DROP FUNCTION ETLWORK_GETWEEKNUMBER
GO CREATE FUNCTION ETLWORK_GETWEEKNUMBER(@DATE DATETIME)
RETURNS INTEGER
AS
BEGIN DECLARE @FIRST_DATE_OF_YEAR DATETIME = DATEADD(YYYY,DATEDIFF(YYYY,0,@DATE),0)
-- DECLARE @MONDAY_OF_WEEK DATETIME = DATEADD(WK,DATEDIFF(WK,0,@DATE),0)
-- DECLARE @PREVIOUS_DATE DATETIME = DATEADD(DAY,-1,@DATE)
DECLARE @WEEK_NUMBER INTEGER -- 如果当前时间是当前年的第一天
IF @DATE = @FIRST_DATE_OF_YEAR
SET @WEEK_NUMBER = 1
-- 星期天是年第一天的情况
ELSE IF (DATEPART(WEEKDAY,@DATE) = 1 AND DATEDIFF(DAYOFYEAR,@FIRST_DATE_OF_YEAR,@DATE)/7 + 1 = DATEPART(WEEK,@DATE))
SET @WEEK_NUMBER = DATEPART(WEEK,@DATE)
-- 星期天不是年第一天的情况
ELSE IF (DATEPART(WEEKDAY,@DATE) = 1 AND DATEDIFF(DAYOFYEAR,@FIRST_DATE_OF_YEAR,@DATE)/7 + 1 <> DATEPART(WEEK,@DATE))
SET @WEEK_NUMBER = DATEPART(WEEK,@DATE) - 1
-- 如果当前天的上一个周日小于年第一天
ELSE IF DATEADD(DAY,-1,DATEADD(WK,DATEDIFF(WK,0,@DATE),0)) < @FIRST_DATE_OF_YEAR
SET @WEEK_NUMBER = 1
-- 当前天前面的一个周日正好是以周日为开始年的 7 倍的天数
ELSE IF DATEDIFF(DAYOFYEAR,@FIRST_DATE_OF_YEAR,DATEADD(DAY,-1,DATEADD(WK,DATEDIFF(WK,0,@DATE),0) ))/7 + 1 = DATEPART(WEEK,@DATE)
SET @WEEK_NUMBER = DATEPART(WEEK,@DATE) + 1
ELSE
SET @WEEK_NUMBER = DATEPART(WEEK,@DATE) RETURN @WEEK_NUMBER
END
GO
为了方便理解,可以查看下面的查询。
DECLARE @DATE DATETIME = '2012-01-29'
DECLARE @FIRST_DATE_OF_YEAR DATETIME = DATEADD(YYYY,DATEDIFF(YYYY,0,@DATE),0) SELECT DATEPART(WEEK,@DATE), -- 一年中的周数,默认以周日开始
DATEADD(WK,DATEDIFF(WK,0,@DATE),0), -- 当前周的周一,默认从周日开始,但是仍然找周一
DATEADD(DAY,-1,DATEADD(WK,DATEDIFF(WK,0,@DATE),0)), -- 当前周先找周一,然后往前一天找到周日
DATEDIFF(DAYOFYEAR,@FIRST_DATE_OF_YEAR,DATEADD(DAY,-1,DATEADD(WK,DATEDIFF(WK,0,@DATE),0))), -- 当前天离年第一天的间隔
DATEDIFF(DAYOFYEAR,@FIRST_DATE_OF_YEAR,DATEADD(DAY,-1,DATEADD(WK,DATEDIFF(WK,0,@DATE),0) ))/7 + 1 -- 按天计算的周数
测试一下,查找不匹配的 Week Number - 30多年的数据结果都匹配,记得要新开一个页面,以免之前 SET DATEFIRST 的影响。
查询部分数据的 WeekNumber。
当然,我感觉写的还是有点复杂,谁解决过类似问题的,期望有人能提出更简洁的写法。
更多 BI 文章请参看 BI 系列随笔列表 (SSIS, SSRS, SSAS, MDX, SQL Server)
如果觉得这篇文章看了对您有帮助,请帮助推荐,以方便他人在 BIWORK 博客推荐栏中快速看到这些文章。
SQL Server - 把星期一(周一)当作每个星期的开始在一年中求取周数的更多相关文章
- SQL SERVER统计服务器所有的数据库(数据库文件)、表(表行数)、字段(各字段)等详细信息
原文:SQL SERVER统计服务器所有的数据库(数据库文件).表(表行数).字段(各字段)等详细信息 USE STAT GO SET NOCOUNT ON IF EXISTS(SELECT 1 FR ...
- Sql Server 获取本周周一
SELECT DATEADD(Day,(@i+1)-(DATEPART(Weekday,getdate())+@@DATEFIRST-1)%7,getdate())
- 模拟实现SQL Server中的datepart(week,date)的功能
本文目录列表: 1.为什么要模拟实现datepart(week,date)的功能 2.具体实现思路 3.T-SQL代码实现逻辑 4.总结语 5.参考清单列表 1.为什么要模拟实现datepart( ...
- 微软BI 系列随笔列表 (SSIS, SSRS, SSAS, MDX, SQL Server)
[公告]本博客于2015年10月起不再更新 新博客文章主要发表在商业智能BI社区: http://www.flybi.net/blog/biwork 博客地图自动分类 文章目录方便更好的导航,阅读文章 ...
- BI 系列随笔列表 (SSIS, SSRS, SSAS, MDX, SQL Server)
微软 BI ETL 架构设计 如何在 ETL 项目中统一管理上百个 SSIS 包的日志和包配置框架 如何管理和记录 SSIS 各个 Task 的开始执行时间和结束时间以及 Task 中添加|删除|修改 ...
- SQL Server时间粒度系列----第1节时间粒度概述
本文目录列表: 1.什么是时间粒度?2.SQL Server提供的时间粒度3.SQL Server时间粒度代码演示 4.SQL Server基准日期 5.总结语6.参考清单列表 什么是时间粒度 ...
- SQL Server时间粒度系列----第7节日历数据表详解
本文目录列表: 1.时间粒度有关描述 2.时间维度有关功能函数3.日历数据表 4.日历数据表数据填充 5.总结语 6.参考清单列表 时间粒度有关描述 将该系列涉及到的时间粒度以及分钟以下的粒度 ...
- SQL Server 2016里TempDb的提升
几个星期前,SQL Server 2016的最新CTP版本已经发布了:CTP 2.4(目前已经是CTP 3.0).这个预览版相比以前的CTP包含了很多不同的提升.在这篇文章里我会谈下对于SQL Ser ...
- SQL Server中的事务日志管理(1/9):事务日志概况
当一切正常时,没有必要特别留意什么是事务日志,它是如何工作的.你只要确保每个数据库都有正确的备份.当出现问题时,事务日志的理解对于采取修正操作是重要的,尤其在需要紧急恢复数据库到指定点时.这系列文章会 ...
随机推荐
- 运用DebugDiag诊断ASP.Net异常
Debug Diagnostic Tool (DebugDiag)是用来帮助诊断IIS/COM+等应用假死.性能差.内存泄露及碎片和崩溃等问题的工具. 本文介绍如何运用DebugDiag诊断特定的AS ...
- buildbot入门系列—介绍篇
一.介绍 1. buildbot是一个开源的基于python的持续集成系统,它能够以下三种方式触发相应的自动构建和测试运行,从而迅速的发现问题所在,同时指出造成这个错误的开发人员,当然我们还可以通过页 ...
- 由ASP.NET所谓前台调用后台、后台调用前台想到HTTP——实践篇(二)
在由ASP.NET所谓前台调用后台.后台调用前台想到HTTP——理论篇中描述了一下ASP.NET新手的三个问题及相关的HTTP协议内容,在由ASP.NET所谓前台调用后台.后台调用前台想到HTTP—— ...
- Java8的新特性以及与C#的比较
函数式接口 VS 委托 在C中,可以使用函数指针来存储函数的入口,从而使得函数可以像变量一样赋值.传递和存储,使得函数的调用变得十分灵活,是实现函数回调的基础.然而函数指针不存在函数的签名信息,甚至可 ...
- 我心中的核心组件~HttpHandler和HttpModule实现图像的缩放与Url的重写
回到目录 说在前 对于资源列表页来说,我们经常会把图像做成N多种,大图,小图,中图等等,很是麻烦,在数据迁移时,更是一种痛快,而如果你把图像资源部署到nginx上,那么这种图像缩放就变得很容易了,因为 ...
- .net生成随机字符串
生成随机字符串的工具类: /// <summary> /// 随机字符串工具类 /// </summary> public class RandomTools { /// &l ...
- SQL SERVER 2005/2008 中关于架构的理解(一)
SQL SERVER 2005/2008 中关于架构的理解(一) 在一次的实际工作中碰到以下情况,在 SQL SERVER 2008中,新建了一个新用户去访问几张由其他用户创建的表,但是无法进行查询, ...
- MySQL5.7.13源码编译安装指南
系统 CenterOs 6.5 1.安装依赖包(cmake make gcc等,其实好多都有了,不需要更新,为了防止世界被破坏,就装下) yum install gcc gcc-c++ -yyum i ...
- 2.Redis常用命令
setget 匹配Keykeys *keys na*keys na?e 判断指定的Key是否存在exists key 删除一个或者多个keydel key//删除一个del key1 key2//删除 ...
- android上引入七牛 上传图片或者文件 最终整理版本(可用)
前言: 以下是引入七牛的步骤,以及在七牛中上传文件和获取文件private 私密地址. 生成上传凭证和获取下载凭证 具体如果使用过程有什么疑问可以加QQ(备注:七牛问题). 1:导入相关的包(注意是4 ...