设为首页 收藏本站
查看: 1166|回复: 0

[经验分享] SQL Server中公用表表达式 CTE 递归的生成帮助数据,以及递归的典型应用

[复制链接]

尚未签到

发表于 2017-7-13 23:32:02 | 显示全部楼层 |阅读模式
  本文出处:http://www.cnblogs.com/wy123/p/5960825.html
  我们在做开发的时候,有时候会需要一些帮助数据,必须需要连续的数字,连续间隔的时间点,连续的季度日期等等
常见很多人利用master库的spt_values系统表,这个当然没有问题
  比如下面这个(没截完,结果是0-2047)
DSC0000.jpg

  
这样也可以使用,但是感觉不够灵活,一是不是随便一个账号都可以访问master数据库的,而是他这里面也只有这么一个连续的数字了,
想要别的结果集就不太弄了,
类似数据可以用公用表表达式CTE的递归来生成
比如上述的0-2047的结果集



;with GenerateHelpData
as
(
select 0 as id
union all
select id+1 from GenerateHelpData where id<2047
)
select id from GenerateHelpData option (maxrecursion 2047);
  可以直接让CTE参数逻辑运算,也可以生成临时表,达到多次重用的目的,这样感觉是不是也很清爽?
  1,生成连续数字(当然数字的起始值,间隔值都可以自定义)



--生成连续数字
;with GenerateHelpData
as
(
select 0 as id
union all
select id+1 from GenerateHelpData where id<2047
)
select id from GenerateHelpData option (maxrecursion 2047);
DSC0001.jpg

  2,CTE递归生成连续日期



--生成连续日期
;with GenerateHelpData
as
(
select cast('2016-10-01' as date) as [Date]
union all
select DATEADD(D,1,[Date]) from GenerateHelpData where [Date]<'2017-01-01'
)
select [Date] from GenerateHelpData;
DSC0002.jpg

  3,生成连续间隔的时间点
  有时候一些统计需要按照一个小时或者半个小时之类的时间间隔做组合,比如统计某天内没半个小时的小时数据等等



--生成连续间隔的时间点
;with GenerateHelpData
as
(
select 1 as id, cast('00:00:00' as time(0)) as timeSection
union all
select id+1 as id,  cast(dateadd(mi,30,timeSection) as time(0)) as timeSection
from GenerateHelpData  where id<49
)
select * from GenerateHelpData
DSC0003.jpg

  当然这里就可以非常灵活了,更骚一点的变形



--更骚一点的变形
;with GenerateHelpData
as
(
select 1 as id, cast('00:00:00' as time(0)) as timeSection
union all
select id+1 as id,  cast(dateadd(mi,30,timeSection) as time(0)) as timeSection
from GenerateHelpData  where id<49
)
select
A.timeSection as timeSectionFrom,
B.timeSection as timeSectionTo,
cast(A.timeSection as varchar(10))+'~'+cast(B.timeSection as varchar(10)) as timeSection
from GenerateHelpData  A inner join GenerateHelpData B on A.id= B.id-1
DSC0004.jpg

  4,生成连续季度的最后一天



DECLARE
@begin_date date = '2014-12-31',
@end_date date = '2016-12-31'
;with GenerateHelpData as
(
select
CAST(    CASE
WHEN RIGHT(@begin_date,5)='12-30'
THEN DATEADD(DAY,1,@begin_date)
ELSE @begin_date
END AS    DATE)
AS EndingDate
UNION ALL
SELECT     
CASE WHEN RIGHT(DATEADD(QQ,1,EndingDate),5)='12-30'
THEN  DATEADD(DAY,1,DATEADD(QQ,1,EndingDate))
ELSE DATEADD(QQ,1,EndingDate)
END AS EndingDate
from GenerateHelpData where EndingDate< @end_date
)
select * from GenerateHelpData
DSC0005.jpg

  通过变形可以生成两个日期间隔之间的的数据



DECLARE
@begin_date date = '2014-12-31',
@end_date date = '2016-12-31'
;with GenerateHelpData as
(
select 1 as id ,
CAST(    CASE
WHEN RIGHT(@begin_date,5)='12-30'
THEN DATEADD(DAY,1,@begin_date)
ELSE @begin_date
END AS    DATE)
AS EndingDate
UNION ALL
SELECT     id+1 as id,
CASE WHEN RIGHT(DATEADD(QQ,1,EndingDate),5)='12-30'
THEN  DATEADD(DAY,1,DATEADD(QQ,1,EndingDate))
ELSE DATEADD(QQ,1,EndingDate)
END AS EndingDate
from GenerateHelpData where EndingDate< @end_date
)
select
A.EndingDate as DateFrom,
B.EndingDate as DateTo,
cast(A.EndingDate as varchar(10))+'~'+cast(B.EndingDate as varchar(10)) as timeSection
from GenerateHelpData  A inner join GenerateHelpData B on A.id= B.id-1
DSC0006.jpg

  需要注意的是,CTE递归的默认次数是100,如果不指定递归次数(option (maxrecursion N);),超出默认最大递归次数之后会报错。
DSC0007.png

  
   ——————————————递归原本很容易使用,本文原本是说用递归生成帮助数据的,有朋友问到递归本身的使用,那就再补充一个DEMO吧———————————————————
  
  补充园友的一个实际应用-20161119
  测试数据:



create table ProuctInfo
(
Id INT,
ParentId INT,
ProuctName VARCHAR(50)
)
INSERT INTO ProuctInfo VALUES (1,0,'镜片')
INSERT INTO ProuctInfo VALUES (2,0,'镜架')
INSERT INTO ProuctInfo VALUES (101,1,'高级镜片')
INSERT INTO ProuctInfo VALUES (102,1,'普通镜片')
INSERT INTO ProuctInfo VALUES (201,2,'高级镜架')
INSERT INTO ProuctInfo VALUES (202,2,'普通镜架')
INSERT INTO ProuctInfo VALUES (1001,101,'高级镜片1')
INSERT INTO ProuctInfo VALUES (1002,102,'普通镜片2')
INSERT INTO ProuctInfo VALUES (2001,201,'高级镜架1')
INSERT INTO ProuctInfo VALUES (2002,202,'普通镜架2')
  原始数据的样子,很普通
DSC0008.png

  创建一个函数,获取当前节点的父节点信息



CREATE FUNCTION dbo.FnGetParentInfo(@id int)
returns varchar(max)
as
begin
declare @name varchar(max)
--查询某一个节点的所有父节点
;with SubTab
as
(
select [ID],[ParentID], cast(ProuctName as varchar(200)) as ProuctName
from ProuctInfo WHERE Id = @id
union all
select a.[ID],a.[ParentID],cast(a.ProuctName+'--->'+b.ProuctName as varchar(200)) as ProuctName
from ProuctInfo a,SubTab b
where a.[ID]=b.[ParentID]
)
select @name = ProuctName from SubTab  where ParentId = 0
return @name
end
  实际效果:
DSC0009.png

  总结:本文演示了几种常用的根据CTE递归生成帮助数据的情况,如果需要帮助数据,可以根据CTE的递归特性做灵活处理。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-393613-1-1.html 上篇帖子: SQL Server中CROSS APPLY和OUTER APPLY的应用详解 下篇帖子: [资料分享]SQL Server 2016/2014/2012/2008简体中文企业版下载+对应补丁
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表