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

[经验分享] 【Microsoft SQL Server 2008 技术内幕:T-SQL语言基础】二、查询篇

[复制链接]

尚未签到

发表于 2016-11-5 09:39:28 | 显示全部楼层 |阅读模式
sql2008 t-sql
单表查询
TOP选项
1. (结合order by)返回的是有固定顺序的游标
2. 可以使用percent关键字
3. 附加属性tiebreaker
    在没有给定所有列的order by次序时,top语句的返回列可能是不确定的,sql server将按照物理顺序返回结果。
    tiebreaker是一个用以确定唯一结果顺序的field或field列表。
4. WITH TIES选项 (相对于tiebreaker)
    除了使用tiebreaker,还可以使用该选项返回具有所有相同结果的行。
    例如 select top(3) field1, field2, field3 from xtable,可能会返回a,b,c行或a,b,d行
    而select top(3) with ties field1, field2, field3 from xtable将返回所有的可能结果行: a,b,c,d
OVER子句
over子句为行定义一个窗口(window),以进行窗口函数(window function, 又分为rankingaggregate)计算。
    传统的聚合(aggregate)函数以group by查询作为操作上下文,每个每组仅返回一个值
    开窗聚合函数使用over子句为上下文,没有数据分组,可以在返回记录中同时使用from, where, group by中的可用字段。
    Ranking function: ROW_NUMBER, RANK, DENSE_RANK, NTITLE
select ROW_NUMBER() over(order by SalesOrderID) as RowNumber
, RANK() over (order by SalesOrderID) as Rank  
, SalesOrderID
, ProductID
, OrderQty
, SUM(OrderQty) over(partition by SalesOrderID) as Total
from SalesLT.SalesOrderDetail as A

查询元数据
Sql server提供了一系列视图,用于获取数据库对象的元数据信息的工具:
目录视图 (Booksonline: catalog views): 提供数据库中各个对象的信息
信息架构视图 (Booksonline: INFORMATION_SCHEMA views): 基于ANSI SQL标准的形式提供元数据信息,不包含Sql server所特有的内容
系统存储过程和函数 (Booksonline: system stored procedures, system functions):
联接查询
1. 左联应用中非常有用的数字序列表,可以用来构造一个连续的结果集作为左联基础:  
set nocount on
if OBJECT_ID('dbo.Nums', 'U') is not null drop table dbo.Nums
create table dbo.Nums(n int not null primary key)
declare @i as int = 1  -- SQL 2008 新语法
begin tran
while @i <=10000
begin
insert into dbo.Nums values(@i)
set @i = @i +1
end
commit tran
set nocount off
select DATEADD(day, n-1, '20060101') as orderdate
from dbo.Nums
where n <= DATEDIFF(day, '20060106', '20081231') + 1
order by orderdate
2. 左联的抵消

  • 如果在左联的where子句中使用了非保留列的表达式作为条件,那么左联效果会被抵消,结果集会变成内联的效果。
  • 因为该非保留列的表达式永远为: NULL<运算符><值>, 其值永远为unkown

3. 多表连接中使用外联容易出现的逻辑错误。下边是2.3点的例子
-- 1. 错误逻辑的例子
select C.CustomerID, O.SalesOrderID, OD.ProductID, OD.OrderQty
from SalesLT.Customer as C
left join SalesLT.SalesOrderHeader as O
on C.CustomerID = O.CustomerID
join SalesLT.SalesOrderDetail as OD
on O.SalesOrderID = OD.SalesOrderID -- 使用了非保留列作条件,将会抵消左联
-- 2. 正解1,连续左联
select C.CustomerID, O.SalesOrderID, OD.ProductID, OD.OrderQty
from SalesLT.Customer as C
left join SalesLT.SalesOrderHeader as O
on C.CustomerID = O.CustomerID
left join SalesLT.SalesOrderDetail as OD -- 继续左联
on O.SalesOrderID = OD.SalesOrderID
-- 3. 正解2,先内联再左联
select C.CustomerID, O.SalesOrderID, OD.ProductID, OD.OrderQty
from SalesLT.SalesOrderHeader as O
join SalesLT.SalesOrderDetail as OD -- 先内联
on O.SalesOrderID = OD.SalesOrderID
right join SalesLT.Customer as C         -- 再右联
on O.CustomerID = C.CustomerID
-- 4. 正解3,类似正解2,使用括号,进行逻辑嵌套即可,代码省略
4. 表关联是的运算顺序为自左至右
5. 在外联查询中使用count应注意它会将外部行业纳入统计,因为它只根据行数进行统计
子查询

  • 分为独立子查询(self-contained subquery),相关子查询(correlated subquery,子查询中引用了外部查询的表)。
  • 查询结果可以返回单值(标量 scalar),多值(multi-valued)或表(table)

-- 返回前一条记录的子查询
-- 注意,这里是最简单的一个例子,效率会比较低
-- 可以把条件转移到where子句以提高效率
-- 或者使用错位联接,效率应该更高
select SalesOrderID, OrderDate
, (select MAX(O2.SalesOrderID)
from SalesLT.SalesOrderHeader as O2
where O2.SalesOrderID < O1.SalesOrderID) as prevorderid
from SalesLT.SalesOrderHeader as O1
-- 连续聚合 (running aggregate)
-- 通常使用连续聚合时应该至少有一个时间这样类型的列来表达时间连续的概念
select orderyear, qty
, (select SUM(O2.qty)
from SalesLT.OrderTotalByYear as O2
where O2.orderyear <= O1.orderyear) as runqty
from SalesLT.OrderTotalByYear as O1
order by orderyear
-- 行为不当的子查询1,返回没下过单的客户
-- 如果子查询的返回有null,则该查询结果永远为空,因为where子句中的条件结果为unknown
select CustomerID, CompanyName
from SalesLT.Customer as C
where CustomerID not in (select CustomerID
from SalesLT.SalesOrderHeader) -- 没有考虑CustomerID为空的情况
-- 最佳实践: 1.必要时设置field为not null。2.时刻注意SQL的三值逻辑中null的处理

-- 行为不当的子查询2,相近名称造成的子查询混淆
-- 造成这个错误一方面由于名字相近
-- 另一方面是由于sql server的搜索策略:当内查询不存在指定的field时,继续搜索外部查询
-- 这种行为无意中将一个独立子查询转换成了相关子查询
create table SalesLT.MyShippers (
shipper_id int not null primary key,
companyname nvarchar(40) not null
)
create table SalesLT.Orders (
custid int not null primary key,
shipperid int not null
)
-- 返回把订单发货给43号客户的发货人
select shipper_id, companyname
from SalesLT.MyShippers
where shipper_id in ( select shipper_id     -- 注意这里不是 shipperid,
from SalesLT.Orders
where custid = 43)
-- 最佳实践:
-- 1. 长远角度应该考虑统一、一致的命名方案
-- 2. 短期角度则应该在子查询的field前指定来源表

运维网声明 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-296033-1-1.html 上篇帖子: SQL server 表分区 小Demo 参考学习 下篇帖子: SQL Server 2008 分区函数和分区表详解
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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

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

扫描微信二维码查看详情

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


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


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


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



合作伙伴: 青云cloud

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