【网学网提醒】:以下是网学会员为您推荐的一些有用Transat-SQL技巧[持续更新中],希望本篇文章对您学习有所帮助。
持续更新中]一些有用Transat-SQL技巧[持续更新中持续更新中
[1]取得当前日期,不包括时间convert(varchar(10),getdate(),120)convert(varchar(10),getdate(),111)详细格式请参考
CONVERT(data_type[(length)],expression[,style])
格式如:yyyy-mm-dd格式如:yyyy/mm/dd
[2]collation排序规则有时连接两个数据库时因为数据库的排序规则[collation]不一样会出现连接两个表时出现如下错误:Msg446,Level16,State9,Line1Cannotresolvecollationconflictforequaltooperation.
可以用如下的语法解决:select*fromdbo.tb_brm_regionwhereregion_idin(selectdistincttms_district_idcollateLatin1_General_BINfromisf_headerwheretms_district_idisnotnull)
其中Latin1_General_BIN可以根据你的需求换成不同的排序规则collation
[3]取得前一个月的第一天和前一个月的最后一天
declare@gdatedatetimeset@gdate=dateadd(Month,-1,dateadd(day,-(day(getdate())-1),getdate()))declare@edatedatetimeset@edate=convert(varchar(10),dateadd(day,-day(getdate()),getdate()),120)
[4]取得一个星期内的数据select*fromtablewheredatetime
=convert(varchar(10),dateadd(d,1,getdate()-DATEPART(dw,getdate())),120)
[5]存储过程调用存储过程的数据集假设我数据库里有个存储过程getMaxId该存储过程没有用output参数,而且已经在很多地方调用,那么我现在要在另外一个存储过程中调用该存储过程,可以使用如下方法:
createprocdoSomeThingascreatetable#tbTempMaxId(maxIdint)insertinto#tbTempMaxIdexecgetmaxidselect*from#tbTempMaxId
具体思路:1.新增一张与存储过程结构一致的临时表2.用INSERT命令将存储过程结果放入临时表中
[6]如何查看SQLSERVER补丁的版本select@@version可以得到如下结果MicrosoftSQLServer2000-8.00.760(IntelX86)200214:22:05Copyright(c)1988-2003MicrosoftDec17
CorporationStandardEditiononWindowsNT5.0(Build2195:ServicePack4)
[7]如何检查存在临时表
在某些情况下可能会检查是否存在临时表,可以使用下面的代码IFOBJECT_ID(N'tempdb..#temp1')ISNOTNULLdroptable#temp1
[8]如何检测临时表存在二ifexists(select*fromdbo.sysobjectswhereid=object_id(N'[dbo].[#TMPcontent]')andOBJECTPROPERTY(id,N'IsUserTable')=1)droptable[dbo].[#TMPcontent]
[9]如何查询一个表的字段以及字段的格式
SELECT表名=casewhena.colorder=1thend.nameelse''end,
表说明=case'end,字段序号=a.colorder,字段名=a.name,标识whena.colorder=1thenisnull(f.value,'')else'
=case=1
when
COLUMNPROPERTY(''end,
a.id,a.name,'IsIdentity')
then
'√'else
主键=caseewhenexists(SELECTandnamein1(WHEREWHEREindididin(=a.iFROMsysobjectswher
xtype='PK'SELECTSELEC
T
nameindid
FROMFROM
sysindexessysindexkeys
d
AND)))
colid=a.colid'√'else''end,
then
类型=b.name,占用字节数=a.length,长度=COLUMNPROPERTY(a.id,a.name,'PRECISION'),小数位数=isnull(COLUMNPROPERTY(a.id,a.name,'Scale'),0),允许空=casewhena.isnullable=1then'√'else''end,
默认值=isnull(e.text,''),字段说明=isnull(g.[value],'')FROMleftinner='U'leftsyscolumnssystypesabonda.xusertype=b.xusertypeona.id=d.idandd.xtype
joinjoin
sysobjects
andjoin
d.name<>'dtproperties'syscommentseona.cdefault=e.id
left
join
sysproperties
g
on
a.id=g.id
and
a.colid=
g.smallidleft=0--where此条件orderbya.id,a.colorderd.name='department'--如果只查询指定表,加上joinsyspropertiesfond.id=f.idandf.smallid
[10]判断两个表的数据是否一致SELECTWHEN)FROM=(SELECTOM表b)N'一致'N'不一致'ENDCASE(SELECT表a)CHECKSUM_AGG(BINARY_CHECKSUM(*))FRCHECKSUM_AGG(BINARY_CHECKSUM(*)
THENELSE
[11]如何查看SQLSERVER补丁的版本select@@version可以得到如下结果MicrosoftSQLServer2000-8.00.760(IntelX86)200214:22:05Copyright(c)1988-2003MicrosoftDec17
CorporationStandardEditiononWindowsNT5.0(Build2195:ServicePack4)
[12]有时候数据库转移服务器常常会因为表所有者的问题导致数据库不能访问。这时候需要更改表的所有者。一般是将表的所有者改为dbo.
1.将某个表的所有者改为dbo.sp_changeobjectowner'表名','dbo'
2.将当前库中所有表的所有者全部更改为dbo.execsp_MSForEachTable'sp_changeobjectowner''?'',''dbo'''因为库中可能有某些表的所有者本来就是dbo,所以执行会有错误消息,不用理会它,执行完毕就OK了
--如果是要用户表/存储过程/视图/触发器/自定义函数一齐改,则用游标(不要理会错误提示)declaretbcursorlocalforselect'sp_changeobjectowner''['+replace(user_name(uid),']',']]')+'].['+replace(name,']',']]')+']'',''dbo'''fromsysobjectswherextypein('U','V','P','TR','FN','IF','TF')andstatus>=0
opentbdeclare@snvarchar(4000)fetchtbinto@swhile@@fetch_status=0beginexec(@s)fetchtbinto@sendclosetbdeallocatetbgo
来源:yes1000/132.htmcnblogs/xiaotao823/archive/2007/07/09/811216.html
==============这篇文章共分三个部分,收集了在互联网上用来处理MSSQL日期时间的几种方法。这里按我收集的先后排列。
第一部分:SQL的本月统计和本周统计本月统计(MySQL)
select*frombookingwheremonth(booking_time)=month(curdate())andyear(booking_time)=year(curdate())本周统计(MySQL)select*fromspf_bookingwheremonth(booking_time)=month(curdate())andweek(booking_time)=week(curdate())
[SQLServer]表名为:tableName时间字段名为:theDate
查询本月的记录select*fromtableNamewhereDATEPART(mm,theDate)=DATEPART(mm,GETDATE
())andDATEPART(yy,theDate)=DATEPART(yy,GETDATE())查询本周的记录select*fromtableNamewhereDATEPART(wk,theDate)=DATEPART(wk,GETDATE())andDATEPART(yy,theDate)=DATEPART(yy,GETDATE())查询本季的记录select*fromtableNamewhereDATEPART(qq,theDate)=DATEPART(qq,GETDATE())andDATEPART(yy,theDate)=DATEPART(yy,GETDATE())
selectdatediff(day,dateadd(mm,datediff(mm,'',getdate()),''),dateadd(mm,datediff(mm,'',getdate()),'1900-02-01'))选择本月信息SELECT*FROM[表名]WHERE(DATEPART(mm,日期)=@month)AND(DATEPART(yy,日期)=@year)参考资料:1、twtpl368.bokee/viewdiary.11124860.html2、hi.baidu/zjcxy/blog/item/5d4de5fc25721efefd037f44.html第二部分:SQL日期格式化应用大全SqlServer中一个非常强大的日期格式化函数SelectCONVERT(varchar(100),GETDATE(),0):0516200610:57AMSelectCONVERT(varchar(100),GETDATE(),1):05/16/06SelectCONVERT(varchar(100),GETDATE(),2):06.05.16SelectCONVERT(varchar(100),GETDATE(),3):16/05/06
SelectCONVERT(varchar(100),GETDATE(),4):16.05.06SelectCONVERT(varchar(100),GETDATE(),5):16-05-06SelectCONVERT(varchar(100),GETDATE(),6):160506SelectCONVERT(varchar(100),GETDATE(),7):0516,06SelectCONVERT(varchar(100),GETDATE(),8):10:57:46SelectCONVERT(varchar(100),GETDATE(),9):0516200610:57:46:827AMSelectCONVERT(varchar(100),GETDATE(),10):05-16-06SelectCONVERT(varchar(100),GETDATE(),11):06/05/16SelectCONVERT(varchar(100),GETDATE(),12):060516SelectCONVERT(varchar(100),GETDATE(),13):1605200610:57:46:937SelectCONVERT(varchar(100),GETDATE(),14):10:57:46:967SelectCONVERT(varchar(100),GETDATE(),20):2006-05-1610:57:47SelectCONVERT(varchar(100),GETDATE(),21):2006-05-1610:57:47.157SelectCONVERT(varchar(100),GETDATE(),22):05/16/0610:57:47AMSelectCONVERT(varchar(100),GETDATE(),23):2006-05-16SelectCONVERT(varchar(100),GETDATE(),24):10:57:47SelectCONVERT(varchar(100),GETDATE(),25):2006-05-16
10:57:47.250SelectCONVERT(varchar(100),GETDATE(),100):0516200610:57AMSelectCONVERT(varchar(100),GETDATE(),101):05/16/2006SelectCONVERT(varchar(100),GETDATE(),102):2006.05.16SelectCONVERT(varchar(100),GETDATE(),103):16/05/2006SelectCONVERT(varchar(100),GETDATE(),104):16.05.2006SelectCONVERT(varchar(100),GETDATE(),105):16-05-2006SelectCONVERT(varchar(100),GETDATE(),106):16052006SelectCONVERT(varchar(100),GETDATE(),107):0516,2006SelectCONVERT(varchar(100),GETDATE(),108):10:57:49SelectCONVERT(varchar(100),GETDATE(),109):0516200610:57:49:437AMSelectCONVERT(varchar(100),GETDATE(),110):05-16-2006SelectCONVERT(varchar(100),GETDATE(),111):2006/05/16SelectCONVERT(varchar(100),GETDATE(),112):20060516SelectCONVERT(varchar(100),GETDATE(),113):1605200610:57:49:513SelectCONVERT(varchar(100),GETDATE(),114):10:57:49:547SelectCONVERT(varchar(100),GETDATE(),
120):2006-05-1610:57:49
SelectCONVERT(varchar(100),GETDATE(),121):2006-05-1610:57:49.700SelectCONVERT(varchar(100),GETDATE(),126):2006-05-16T10:57:49.827SelectCONVERT(varchar(100),GETDATE(),130):18??????????142710:57:49:907AMSelectCONVERT(varchar(100),GETDATE(),131):18/04/142710:57:49:920AM
常用:SelectCONVERT(varchar(100),GETDATE(),8):10:57:46SelectCONVERT(varchar(100),GETDATE(),24):10:57:47SelectCONVERT(varchar(100),GETDATE(),108):10:57:49SelectCONVERT(varchar(100),GETDATE(),12):060516SelectCONVERT(varchar(100),GETDATE(),23):2006-05-16参考资料:webwoo.net/bc/bencandy-26-14479-1.htm第三部分:SQLServer各种日期计算方法SQLServer各种日期计算方法出处:CSDN.NET[2005-02-2210:12:52]作者:xpilot责任编辑:lujiezhen
通常,你需要获得当前日期和计算一些其他的日期,例如,你的程序可能需要判断一个月的第一天或者最后一天。你们大部分人大概都知道怎样把日期进行分割(年、月、日等),然后仅仅用分割出来的年、月、日等放在几个函数中计算出自己所需要的日期!在这篇文章里,我将告诉你如何使用DATEADD和DATEDIFF函数来计算出在你的程序中可能你要用到的一些不同日期。被过滤广告
在使用本文中的例子之前,你必须注意以下的问题。大部分可能不是所有例子在不同的机器上执行的结果可能不一样,这完全由哪一天是一个星期的第一天这个设置决定。第一天(DATEFIRST)设定决定了你的系统使用哪一天作为一周的第一天。所有以下的例子都是以星期天作为一周的第一天来建立,也就是第一天设置为7。假如你的第一天设置不一样,你可能需要调整这些例子,使它和不同的第一天设置相符合。你可以通过@@DATEFIRST函数来检查第一天设置。
为了理解这些例子,我们先复习一下DATEDIFF和DATEADD函数。DATEDIFF函数计算两个日期之间的小时、天、周、月、年等时间间隔总数。DATEADD函数计算一个日期通过给时间间隔加减来获得一个新的日期。要了解更多的DATEDIFF和DATEADD函数以及时间间隔可以阅读微软联机帮助。
使用DATEDIFF和DATEADD函数来计算日期,和本来从当前日期转换到你需要的日期的考虑方法有点不同。你必须从时间间隔这个方面来考虑。比如,从当前日期到你要得到的日期之间有多少时间间隔,或者,从今天到某一天(比如1900-1-1)之间有多少时间间隔,等等。理解怎样着眼于时间间隔有助于你轻松的理解我的不同的日期计算例子。
一个月的第一天
第一个例子,我将告诉你如何从当前日期去这个月的最后一天。请注意:这个例子以及这篇文章中的其他例子都将只使用DATEDIFF和DATEADD函数
来计算我们想要的日期。每一个例子都将通过计算但前的时间间隔,然后进行加减来得到想要计算的日期。
这是计算一个月第一天的SQL脚本:SELECTDATEADD(mm,DATEDIFF(mm,0,getdate()),0)
我们把这个语句分开来看看它是如何工作的。最核心的函数是getdate(),大部分人都知道这个是返回当前的日期和时间的函数。下一个执行的函数DATEDIFF(mm,0,getdate())是计算当前日期和“1900-01-0100:00:00.000”这个日期之间的月数。记住:时期和时间变量和毫秒一样是从“1900-01-0100:00:00.000”开始计算的。这就是为什么你可以在DATEDIFF函数中指定第一个时间表达式为“0”。下一个
函数是DATEADD,增加当前日期到“1900-01-01”的月数。通过增加预定义的日期“1900-01-01”和当前日期的月数,我们可以获得这个月的第一天。另外,计算出来的日期的时间部分将会是“00:00:00.000”。
这个计算的技巧是先计算当前日期到“1900-01-01”的时间间隔数,然后把它加到“1900-01-01”上来获得特殊的日期,这个技巧可以用来计算很多不同的日期。下一个例子也是用这个技巧从当前日期来产生不同的日期。
本周的星期一
这里我是用周(wk)的时间间隔来计算哪一天是本周的星期一。
SELECTDATEADD(wk,DATEDIFF(wk,0,getdate()),0)
一年的第一天
现在用年(yy)的时间间隔来显示这一年的第一天。
SELECTDATEADD(yy,DATEDIFF(yy,0,getdate()),0)
季度的第一天
假如你要计算这个季度的第一天,这个例子告诉你该如何做。
SELECTDATEADD(qq,DATEDIFF(qq,0,getdate()),0)
当天的半夜
曾经需要通过getdate()函数为了返回时间值截掉时间部分,就会考虑到当前日期是不是在半夜。假如这样,这个例子使用DATEDIFF和DATEADD函数来获得半夜的时间点。
SELECTDATEADD(dd,DATEDIFF(dd,0,getdate()),0)
深入DATEDIFF和DATEADD函数计算
你可以明白,通过使用简单的DATEDIFF和DATEADD函数计算,你可以发现很多不同的可能有意义的日期。
目前为止的所有例子只是仅仅计算当前的时间和“1900-01-01”之间的时间间隔数量,然后把它加到“1900-01-01”的时间间隔上来计算出日期。假定你修改时间间隔的数量,或者使用不同的时间间隔来调用DATEADD函数,或者减去时间间隔而不是增加,那么通过这些小的调整你可以发现和多不同的日期。
这里有四个例子使用另外一个DATEADD函数来计算最后一天来分别替换DATEADD函数前后两个时间间隔。上个月的最后一天
这是一个计算上个月最后一天的例子。它通过从一个月的最后一天这个例子上减去3毫秒来获得。有一点要记住,在SqlServer中时间是精确到3毫秒。这就是为什么我需要减去3毫秒来
获得我要的日期和时间。
SELECTdateadd(ms,-3,DATEADD(mm,DATEDIFF(mm,0,getdate()),0))
计算出来的日期的时间部分包含了一个SqlServer可以记录的一天的最后时刻(“23:59:59:997”)的时间。
去年的最后一天
连接上面的例子,为了要得到去年的最后一天,你需要在今年的第一天上减去3毫秒。
SELECTdateadd(ms,-3,DATEADD(yy,DATEDIFF(yy,0,getdate()),0))
本月的最后一天
现在,为了获得本月的最后一天,我需要稍微修改一下获得上个月的最后一天的语句。修改需要给用DATEDIFF比较当前日期和“1900-01-01”返回的时间间隔上加1。通过加1个月,我计算出下个月的第一天,然后减去3毫秒,这样就计算出了这个月的最后一天。这是计算本月最后一天的SQL脚本。
SELECTdateadd(ms,-3,DATEADD(mm,DATEDIFF(m,0,getdate())+1,0))
本年的最后一天
你现在应该掌握这个的做法,这是计算本年最后一天脚本
SELECTdateadd(ms,-3,DATEADD(yy,DATEDIFF(yy,0,getdate())+1,0))。
本月的第一个星期一
好了,现在是最后一个例子。这里我要计算这个月的第一个星期一。
这是计算的脚本。
selectDATEADD(wk,DATEDIFF(wk,0,dateadd(dd,6-datepart(day,getdate()),getdate())),0)
在这个例子里,我使用了“本周的星期一”的脚本,并作了一点点修改。修改的部分是把原来脚本中“getdate()”部分替换成计算本月的第6天,在计算中用本月的第6天来替换当前日期使得计算可以获得这个月的第一个星期一。
总结
我希望这些例子可以在你用DATEADD和DATEDIFF函数计算日期时给你一点启发。通过使用这个计算日期的时间间隔的数学方法,我发现为了显示两个日期之间间隔的有用历法是有价值的。注意,这只是计算出这些日期的一种方法。要牢记,还有很多方法可以得到相同的计算结果。假如你有其他的方法,那很不错,要是你没有,我希望这些例子可以给你一些启发,当你要用DATEADD和DATEDIFF函数计算你程序可能要用到的日期时。--------------------------------------------------------------附录,其他日期处理方法
1)去掉时分秒declare@datetimeset@=getdate()--'2003-7-110:00:00'SELECT@,DATEADD(day,DATEDIFF(day,0,@),0)
2)显示星期几selectdatename(weekday,getdate())
3)如何取得某个月的天数declare@mintset@m=2--月份selectdatediff(day,'2003-'+cast(@masvarchar)+'-15','2003-'+cast(@m+1asvarchar)+'-15')另外,取得本月天数selectdatediff(day,cast(month(GetDate())asvarchar)+'-'+cast(month(GetDate())asvarchar)+'-15',cast(month(GetDate())asvarchar)+'-'+cast(month(GetDate())+1asvarchar)+'-15')或者使用计算本月的最后一天的脚本,然后用DAY函数区最后一天SELECTDay(dateadd(ms,-3,DATEADD(mm,DATEDIFF(m,0,getdate())+1,
0)))
4)判断是否闰年:SELECTcaseday(dateadd(mm,2,dateadd(ms,-3,DATEADD(yy,DATEDIFF(yy,0,getdate()),0))))when28then'平年'else'闰年'end或者selectcasedatediff(day,datename(year,getdate())+'-02-01',dateadd(mm,1,datename(year,getdate())+'-02-01'))when28then'平年'else'闰年'end
5)一个季度多少天declare@mtinyint,@timesmalldatetimeselect@m=month(getdate())select@m=casewhen@mbetween1and3then1when@mbetween4and6then4when@mbetween7and9then7else10endselect@time=datename(year,getdate())+'-'+convert(varchar(10),@m)+'-01'selectdatediff(day,@time,dateadd(mm,3,@time))
作者Blog:blog.csdn.net/xpilot/
附:我在实际应用中的例子:
获取本月的点击,使用第一部分提供的方法,即detepartselect*fromnews_hitswhereDATEPART(mm,ReadTime)=DATEPART(mm,GETDATE())andDATEPART(yy,ReadTime)=DATEPART(yy,GETDATE())
获取本月的点击,使用来自于asp(vbscript)的思维,即datediffselect*fromnews_hitswhereDATEDIFF(MM,ReadTime,GETDATE())=0--DATEPART(mm,ReadTime)=DATEPART(mm,GETDATE())andDATEPART(yy,ReadTime)=DATEPART(yy,GETDATE())获取本周的点击select*fromnews_hitswhereDATEDIFF(WW,ReadTime,GETDATE())=0获取本周的第一天(来自于第三部分的方法)SELECTDATEADD(wk,DATEDIFF(wk,0,getdate()),0)
用EXISTS避免重复插入已经存在的数据
insertintodomain_branch(domain_id,branch_id,update_user_id,update_date,obsoleted)select'M000042001',branch_id,'S700010000',getdate(),'F'fromdomain_branchb1wheredomain_id='M000032001'andnotEXISTS(select*fromdomain_branchb2whereb1.branch_id=b2.branch_idandb2.domain_id='M000042001')
用递归的方式获取树型关系表中的某个分支的所有子节点
createfunctiondbo.f_temp_rollout_fixMultMgr(@groupIdvarchar(12))returns@tGroupIdtable(groupIdvarchar(12),levint)begindeclare@Countasintset@count=1
insert@tgroupIdselect@groupid,@count
while@@rowcount<>0beginset@count=@count+1insert@tgroupidselectgroup_id,@countfromoc_test_group_temp_rolloutg,@tgroupidtgwhereg.under_group_id=tg.groupidandlev=@count-1endreturnend
T-SQL笔记1:SELECT及SELECT高级应用
T-SQL笔记1:SELECT及SELECT高级应用
本章摘要1:安装AdventureWorks2:基本运算符和表达式3:between4:like5:escape
6:TOP7:GROUPBY7.1:GROUPBYALL7.2:HAVING8:SELECT字句技术8.1:使用DISTINCT消除重复值8.2:返回拼接的结果8.3使用INTO字句9:子查询9.1:子查询类型9.2:代替表达式的查询
9.3:多层嵌套
10:比较使用EXISTS和IN的查询
11:联接11.1:使用衍生表
11.2:UNION12:TABLESAMPLE
13:公共表表达式common_table_expression
1:安装AdventureWorks:本系列笔记均基于AdventureWorks数据库,有关AdventureWorks的安装帮助如下:在ManagementStudio
工具栏上,单击“文件文件”,指向“打开打开”,文件打开然后单击“文件文件”。文件浏览到文件instawdb.sql,并单击“打开打开”。该文件的默认位置打开为C:\ProgramFiles\MicrosoftSQLServer\90\Tools\Samples\AdventureWorksOLTP。
运行脚本之前,在脚本中找到语句SET@data_path=@sql_path+'
AWDB\';,并更改该语句使其指向instawdb.sql脚本的位置。例如,SET@data_path='C:\ProgramFiles\MicrosoftSQLServer\90\Tools\Samples\AdventureWorksOLTP\';。
执行脚本。
2:基本运算符和表达式:
运算符!=描述略
!>!<<<=<>=>>=ALLANYBETWEENCONTAINSESCAPEEXISTSFREETEXTINISNOTNULLISNULLLIKENOTBETWEENNOTINNOTLIKESOME
略略略略略略略略比较标量值和单列集中的值。比较标量值和单列集中的值。SOME和ANY是等效的自动根据SQL的型别进行取值为单词或短语执行模糊搜索指定要以字面值形式搜索,而不是被解释为通配符指定一个子查询,测试行是否存在根据意思,而不是字面值来搜索数据中的单词WHEREcolorin(‘red’,‘blue’)略检测NULL值根据通配符进行模式匹配略略略比较标量值和单列集中的值。SOME和ANY是等效的
3:between:
使用:selectSalesOrderID,ShipDatefromSales.SalesOrderHeaderwhereShipDatebetween'7/28/2002'and'7/29/2002'
结果:将会返回17条语句。
也许有人会用,使用:where'7/28/2002' 4:like:
存在如下通配符,%:0~N个任意字符;_:1个字符;[]:指定范围或列表中的任何单个字符;[^]:指定不再范围中的任何单个字符;
5:escape:wherenamelike‘b/B%’escape‘/’解析:表示全部以‘b/B’开头的name,其中/不理解为通配符。
6:TOP:top允许根据定义的行的数量或者百分比查询出开始的N行。如:
selecttop10from…
或者:declare@percentagefloatset@percentage=1selecttop(@percentage)percent*fromSales.SalesOrderHeader
7:GROUPBY:指定用来放置输出行的组。如果SELECT子句中包含聚合函数,则GROUPBY将计算每组的汇总值。
上面这句话不太好理解,更好的理解应该解释为:“由于在SELECT字句中使用了聚合函数,未聚合的列必须出现由于在字句中使用了聚合函数,子句中。在GROUPBY子句中。”
selectOrderDate,sum(totalDue)TotalDueByOrderDatefromSales.SalesOrderHeaderwhereShipDatebetween'7/28/2002'and'7/29/2002'groupbyOrderDate
结果:(2行受影响)
7.1:GROUPBYALL:在上面的代码中,加入ALL,即:selectOrderDate,sum(totalDue)TotalDueByOrderDatefromSales.SalesOrderHeaderwhereShipDatebetween'7/28/2002'and'7/29/2002'--gro
upbyOrderDategroupbyallOrderDate
结果:Warning:NullvalueiseliminatedbyanaggregateorotherSEToperation.(1124行受影响)
这说明:ALL包含所有组和结果集,甚至包含那些其中任何行都不满足WHERE子句指定的搜索条件的组和结果集。如果指定了ALL,将对组中不满足搜索条件的汇总列返回空值。
7.2:HAVING:指定组或聚合的搜索条件。HAVING只能与SELECT语句一起使用。HAVING通常在GROUPBY子句中使用。如果不使用GROUPBY子句,则HAVING的行为与WHERE子句一样。相当于对GROUP之前的查询内容进行再一次的条件检索。
以下示例使用简单HAVING子句从SalesOrderDetail表中检索超过$100000.00的每个SalesOrderID的总计。SELECTSalesOrderID,SUM(LineTotal)ASSubTotalFROMSales.SalesOrderDetail--whereModifiedDatebetween'7/28/2002'and'7/29/2002'GROUPBYSalesOrderIDHAVINGSUM(LineTotal)>100000.00--HAVINGSalesOrderID=43875--HAVINGModifiedDatebetween'7/28/2002'and'7/29/2002'--errorORDERBYSalesOrderID;
8:SELECT字句技术:SELECT字句技术有很多,除了最简单的拼接等,下面介绍个人认为最有用的。
8.1:使用DISTINCT消除重复值:select*FROMHumanResources.Employee
结果:(290行受影响)selectDISTINCTHireDateFROMHumanResources.Employee
结果:(164行受影响)
说明已经将重复的抵消了。
8.2:返回拼接的结果:DECLARE@Shiftsvarchar(20)SET@Shifts=''SELECT@Shifts=@Shifts+s.Name+','FROMHumanResources.ShiftsSELECT@Shifts
返回的结果为:Day,Evening,Night,
这对于我们处理简单的查询并提高效率有很大的好处。
8.3使用INTO字句INTO字句用来创建新表(对我来说便是备份数据)。
一种典型的用法是复制数据到新表(这个新表可以被创建为永久表、临时表或全局临时表),如下代码:SELECTCustomerID,Name,SalesPersonID,DemographicsINTOStore_ArchiveFROMSales.Store
结果:(701行受影响)说明,1:创建了新表Store_Archive,2:有701行数据被复制到了Store_Archive。
当然,如果你仅仅想创建新表,而不想复制任何数据,有一个简洁的方法是:SELECTCustomerID,Name,SalesPersonID,DemographicsINTOStore_Archive
FROMSales.StoreWHERE1=0
9:子查询:子查询是一个嵌套在SELECT、INSERT、UPDATE或DELETE语句或其他子查询中的查询。任何允许使用表达式的地方都可以使用子查询。
联接总是可以表示为子查询。子查询经常(但不总是)可以表示为联接。这是因为联接是对称的:无论以何种顺序联接表A和B,都将得到相同的结果。而对子查询来说,情况则并非如此。
使用联接而不使用子查询处理该问题及类似问题的一个不同之处在于,联接使您可以在结果中显示多个表中的
列。例如,如果要在结果中包括产品子类别的名称,则必须使用联接版本。
9.1:子查询类型:
可以在许多位置指定子查询(必须全部掌握):
?
使用别
名。有关详细信息,请参阅使用别名的子查询。
?
使用
IN
或
NOT
IN。有关详细信息,
请参阅使用
IN
的子查询和使用
NOT
I
N
的子查询。
?
在
UPDATE、DELET
E
和
INSERT
语句中。有关详细信息,
请参阅
UPDATE、DELETE
和
IN
SERT
语句中的子查询。
?
使用比较运算符。
有关详细信息,请参阅使用比较运算符的子查询
。
?
使用
ANY、SOME
或
ALL。有关
详细信息,请参阅用
ANY、SOME
或
A
LL
修改的比较运算符。
?
使用
EXISTS
或
NOT
EXISTS。有关详细信息,请
参阅使用
EXISTS
的子查询和使用
NO
T
EXISTS
的子查询。
?
代替表达式。有
关详细信息,请参阅用于替代表达式的子查询。9.2:代替表达式的查询:
必须着重说说代替表达式的子查询。在Transact-SQL中,除了在ORDERBY列表中以外,在SELECT、UPDATE、INSERT和DELETE语句中任何能够使用表达式的地方都可以用子查询替代。
以下示例说明如何使用此增强功能。此查询找出所有山地车产品的价格、平均价格以及两者之间的差价。
USEAdventureWorks;GOSELECTName,ListPrice,(SELECTAVG(ListPrice)FROMProduction.Product)ASAverage,ListPrice-(SELECTAVG(ListPrice)FROMProduction.Product)ASDifferenceFROMProduction.ProductWHEREProductSubcategoryID=1
9.3:9.3:多层嵌套
子查询自身可以包括一个或多个子查询。一个语句中可以嵌套任意数量的子查询。
以下查询将查找作为销售人员的雇员的。
UseAdventureWorks;GOSELECTLastName,FirstNameFROMPerson.Contact
WHEREContactIDIN(SELECTContactIDFROMHumanResources.EmployeeWHEREEmployeeIDIN(SELECTSalesPersonIDFROMSales.SalesPerson)
10:比较使用EXISTS和IN的查询:
以下示例比较了两个语义等同的查询。第一个查询使用EXISTS,第二个查询使用IN。
USEAdventureWorks;GOSELECTa.FirstName,a.LastNameFROMPerson.ContactASaWHEREEXISTS(SELECT*FROMHumanResources.EmployeeASbWHEREa.ContactId=b.ContactIDANDa.LastName='Johnson');GO
下面的查询使用IN。
USEAdventureWorks;
GOSELECTa.FirstName,a.LastNameFROMPerson.ContactASaWHEREa.LastNameIN(SELECTa.LastNameFROMHumanResources.EmployeeASbWHEREa.ContactId=b.ContactIDANDa.LastName='Johnson');GO
以下是其中任一查询的结果集。
FirstName
LastName
------------------
-----------------------------------------BarryDavidWillis(3row(s)affected)JohnsonJohnsonJohnson
11:11:联接通过联接,可以从两个或多个表中根据各个表之间的逻辑关系来检索数据。联接条件中用到的列不必具有相同的名称或相同的数据类型。但如果数据类型不相同,则必须兼容,或者是可由SQLServer进行隐式转换的类型。
联接可分为以下几类:
?
内部联接(典型的联接运算,使用类似于
=
或
<>
的比较运算符)。内部联接包括同等联接
和自然联接。
内部联接使用比较运算符根据每
个表的通用列中的值匹配两个表中的行。例如,检
索
students
和
courses
表
中学生标识号相同的所有行。
?
外部联接。外部联
接可以是左向外部联接、右向外部联接或完整外部
联接。
在
FROM
子句中可以用下列某一
组关键字来指定外部联接:
?
LEFT
JOIN
或
LEFT
OUTER
JOIN。
左
向外部联接的结果集包括
LEFT
OUTER
子句中指定的左表的所有行,而不仅仅是联接列
所匹配的行。如果左表的某一行在右表中没有匹配
行,则在关联的结果集行中,来自右表的所有选择
列表列均为空值。
?
RIGHT
JOIN
或
RIGHT
OUTER
JOIN
右向外部
联接是左向外部联接的反向联接。将返回右表的所
有行。如果右表的某一行在左表中没有匹配行,则
将为左表返回空值。
?
FULL
JOIN
或
FULL
OUTER
JOIN
完整外部联
接将返回左表和右表中的所有行。当某一行在另一
个表中没有匹配行时,另一个表的选择列表列将包
含空值。如果表之间有匹配行,则整个结果集行包
含基表的数据值。
?
交叉联接
交叉联接将返回
左表中的所有行。左表中的每一行均与右表中的所
有行组合。交叉联接也称作笛卡尔积。11.1:使用衍生表:衍生表是指在FROM字句中作为表的SELECT语句。SELECTDISTINCTs.PurchaseOrderNumberFROMSales.SalesOrderHeaders
INNERJOIN(SELECTSalesOrderIDFROMSales.SalesOrderDetailWHEREUnitPriceBETWEEN1000AND2000)dONs.SalesOrderID=d.SalesOrderID
11.2:UNION:
将两个或更多查询的结果合并为单个结果集,该结果集包含联合查询中的所有查询的全部行。
下面列出了使用UNION合并两个查询结果集的基本规则:
?
所有查询中
的列数和列的
顺序必须相同。
?
数据类型必须兼容。
SELECTProductModelID,NameFROMProduction.ProductModelWHEREProductModelIDNOTIN(3,4)UNIONSELECTProductModelID,NameFROMdbo.GlovesORDERBYName;
12:TABLESAMPLE:TABLESAMPLE子句将从FROM子句中的表返回的行数限制到样本数或行数的某一百分比。例如:SELECTFirstName,LastNameFROMPerson.PersonTABLESAMPLE(10PERCENT);SELECTFirstName,LastNameFROMPerson.PersonTABLESAMPLE(100ROWS);
13:公共表表达式common_table_expression:指定临时命名的结果集,这些结果集称为公用表表达式(CTE)。该表达式源自简单查询,并且在单条SELECT、INSERT、UPDATE或DELETE语句的执行范围内定义。该子句也可用在CREATEVIEW语句中,作为该语句的SELECT定义语句的一部分。公用表表达式可以包括对自身的引用。这种表达式称为递归公用表表达式。USEAdventureWorks;GOWITHDirReps(ManagerID,DirectReports)AS(
SELECTManagerID,COUNT(*)FROMHumanResources.EmployeeASeWHEREManagerIDISNOTNULLGROUPBYManagerID)SELECTManagerID,DirectReportsFROMDirRepsORDERBYManagerID;GO