SQL学习--Select(⼀)TOP、派⽣表、连接、谓词TOP关键字
1select top 4 WITH TIES t.title,sum(s.qty)as totalSales from sales s
2 left join titles t on s.title_id=t.title_id
3 group by t.title
4 order by totalSales
View Code
这⾥的top 4 WITH TIES 是获取前4条数据且需要重复值,但是请注意这个重复值是会影响返回数据的⾏
⽐如,重复值在第4⾏出现那么可能就会返回5⾏数据(2个值的重复)
如果重复值在第⼆⾏或者第三⾏出现则只返回4条数据
另外需要注意的TOP N 需要与order by⼀同使⽤否则会报错。
TOP N的缺点
  ⽆法返回与查询的GroupBy⼦句中的被分组的结果集的前⼏条,
  这就标明TOP N指向的是整个查询的结果集,⽽不是指向源表中或已被分类的组中的⾏。
  TOP N的运算顺序在整个sql关键字的后边。实例:
1select t.state,t.stor_name,sum(s.qty)as totalSales
2from sales s join stores as t on s.stor_id=t.stor_id
3 group by t.state,t.stor_name
4 order by totalSales desc
5
6select top 1 t.state,t.stor_name,sum(s.qty)as totalSales
7from sales s join stores as t on s.stor_id=t.stor_id
8 group by t.state,t.stor_name
9 order by totalSales desc
View Code
派⽣表
  select除了直接引⽤表或试图外还可以使⽤派⽣表(⼦查询),也叫逻辑表。它可以像表或视图⼀样查询和链接
select au_lname,au_fname from (select * from authors) as a
  这个派⽣表是由select * from authors语法创建的,此处可以插⼊任何⼀个有效的查询,
  但需要注意这⾥使⽤别名且必须使⽤别名。因为T-SQL⽀持⾮列表的Select语句。
1select * from (
2select'Blotchet-Halls'as weightClass ,0as lowBound ,112as highBound
3    union all
4select'DeFrance'as weightClass ,112as lowBound ,118as highBound
5    union all
6select'Green'as weightClass ,127as lowBound ,135as highBound
7 )as w
8 order by w.lowBound
View Code
  例⼦中这个表不存在只是通过union all链接形成了⼀张逻辑表,逻辑表同时可以与表或试图相连接连接
  在内连接中,从句顺序s不会影响到结果集。如果A等于B,那么B就等于A。
⽽在外连接中则不然,表中的顺序直接影响结果集中包含的哪些⾏及值
1select sum(d.UnitPrice*d.Quantity) as totalOrders from Orders o
2left join[Order Details] d on o.OrderID+10=d.OrderID
3left join Products p on d.ProductID=p.ProductID
4
5select sum(d.UnitPrice*d.Quantity) as totalOrders from[Order Details] d
6left join Products p on d.ProductID=p.ProductID
7left join[Orders] o on o.OrderID+10=d.OrderID
8--连接部分的先后顺序改变了
View Code
在例⼦中故意把OrderID+10造成不匹配,观察两次查询的运算结果,并不相同。
因为第⼀个查询中引起的表Orders和Order Details的不匹配是在对列UnitPrice*Quantity汇总前,
⽽第⼆个查询的不匹配是发⽣在汇总后。第⼆个查询的情况下,会得到所有Details中的所有项的总和,⽆论他与Orders是否匹配,⽽在第⼀个查询中就不是这样了。
看⼀下在2个查询中不匹配的数据有哪些
1select o.OrderDate,d.UnitPrice,d.Quantity from Orders o
2left join[Order Details] d on o.OrderID+10=d.OrderID
3left join Products p on d.ProductID=p.ProductID
4where o.OrderDate is null or d.UnitPrice is null
View Code
执⾏语句后,会发现正是我通过OrderID+10的那10条数据。
所以在使⽤外部链接存在不匹配链接的可能,所以⼀定要⼩⼼。
谓词
  BETWEEN
    他的作⽤是判断⼀个给定值是否落在了两个值之间的内部
1select au_lname,au_fname from authors
2where au_lname between's'and'zz'
3order by au_lname
View Code
带有⼦集、变量和表达式的语句
1Declare@au_id id
2select@au_id=(select max(au_id) from titleauthor)
3
4select au_lname,au_fname from authors
5where au_id between (select min(au_id) from titleauthor) and (ISNULL(@au_id,'zzzzzzzzzzzzz'))
6order by au_lname
View Code
尽管AND很⽅便,但有时候很难界定多个区间的范围。此时不如⽤逆向思维排除法,扣去必定发⽣的,就能得到不会发⽣的  LIKE
  检测⼀个值对字符串的模式匹配
  %:表⽰匹配任意字符
  _:表⽰只匹配⼀个字符
  [ab]:表⽰匹配a、b、ab
  EXISTS
  把⼦查询作为单独参数返回的判断函数。在EXISTS前边加NOT表⽰否定
  EXISTS在指定⼀个⼦查询,检测⾏的存在。遍历循环外表,然后看外表中的记录有没有和内表的数据⼀样的。匹配上就将结果放⼊结果集中
  如果成⽴则返回true不成⽴则返回false。如果返回的是true的话,则该⾏结果保留,如果返回的是false的话,则删除该⾏,最后将得到的结果返回。
  在EXISTS中NULL值的处理
1select title from titles t
2where EXISTS(--此时为true
3select*from(
4select*from sales
5union all
6select null,null,null,90,null,null
7    ) s--通过union all插⼊了⼀条为null,qty为90的数据
多表left join8where t.title_id=s.title_id and s.qty>75)
View Code
  这个查询结果最后还是空。为什么呢?最后插⼊的null的那条数据是满⾜where qty>75的为什么没有返回?
  答案是即便是返回了但是连接条件是titleid=titleid,⽽插⼊的数据titleID=null,null怎么可能等于null呢?null谁都不等于,也不等于⾃⼰  EXISTS和IN
  把EXISTS换成IN有⼀些特殊性。
1select Count(title) from titles t
2where t.title_id in(select title_id from sales)--16条
3
4select Count(title) from titles t
5where t.title_id not in(select title_id from sales)--2条
6
7select Count(title) from titles t
8where t.title_id not in(select title_id from sales union all select null)--0条
View Code
  IN在⽐较⼀个值与NULL是否相等的表达式总是返回NULL,所以不符合检测,原因是其他⾏与null在同⼀列表所以返回null。这是IN和EXISTS的区别
  另外如果查询语句使⽤了not in 那么内外表都进⾏全表扫描,没有⽤到索引;⽽not extsts 的⼦查询依然能⽤到表上的索引。所以⽆论那个表⼤,⽤not exists都⽐not in要快。
  如果⼦查询得出的结果集记录较少,主查询中的表较⼤且⼜有索引时应该⽤in, 反之如果外层的主查询记录较少,⼦查询中的表⼤,⼜有索引时使⽤exists。
  同时不管使⽤哪种⼦查询的⽅式都是⽐表连接要慢很多的,所以建议使⽤连接的⽅式。
  结果集为空
  EXISTS的另外⼀种⽤法是检测结果集的多⾏。
  if exists(select * from sales)肯定要⽐if(select count(*) from sales )>0快的多,⽽且提供了⼀种不检查系统对象来确定表是否为空的快速⽅法
  where和having以外的EXISTS
  EXISTS还可以做很多其他的⼯作,不仅仅是查询返回的⾏。通过派⽣表还可以在case表达式和from⼦句中
  select case when EXISTS(Select * from titleauthor where au_id=a.au_id) then 'true' else 'false' end from authors a  IN
1select*from titles where title_id in
2 (
3select title_id from (
4select top99999 title_id,count(*) as numberOrder from sales group by title_id order by numberOrder desc
5    )s
6 )
View Code

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。