单表查询

1、 select 语句元素

(1)“逻辑查询处理” 是SQL 标准定义的概念性路径,SQL Server 引擎会重新排列、优化处理,保持最终结果与逻辑查询处理相同。

  (2)   子句键入顺序和逻辑处理顺序不一致,子句逻辑处理顺序:  from 、where 、group by 、having 、 select 、order by

(3)建议使用分号终止语句、提高代码可读性、避免语义模糊

 

 

2、from 子句

(1) from 语句 是逻辑化处理的第一个查询子句

(2) 在没有使用order by 的时候返回是没有顺序的

(3)用于指定将要查询的表

3、where

(1) where 用于筛选 from 阶段返回的的行

(2) 只返回逻辑表达式计算结果为true的行、注意T-SQL 使用三值谓语逻辑,计算结果处理TRUE 、FALSE 、还有 UNKNOW

(3)对于逻辑表达式、SQL Server 将评估是否使用索引

 

3、Group By

(1) 在where 塞选之后,对结果分组、组是根据group by 子句中的元素确定的

(2) group by 后面所跟的元素可以是一个 、也可以是 多个元素 、多个元素工程唯一组合分组

from Sales.Orders
where custid = 71
group by empid ,year(orderdate)

(3) group by 分组之后,所有group by 后面的操作 having 、select 都是对组进行操作的,而不是对行

(4) 在最终返回结果,每组都是由一个行来表示、这意味着,group by 后续的操作 指定的所有表达式都必须是一个标量(单值)

(5) 由于 group by 后面的元素 ,对于每个组内都是相同的,所以在group by 后续子句中,即使 这些元素是行、但是也可以直接使用,如下

select empid, year(orderdate) as orderyear
from Sales.Orders
where custid = 71
group by empid ,year(orderdate);

 

(6)不参与到group by 列表中的元素,只能做聚合函数输出 ,如 count 、sum

(7)除了count(*)之外,所以的聚合函数都会忽略 NULL 标记。如数字为“3、10、NULL、10、10” 的qty列、count(*)为5 ,count(qty)为4

(8)distinct 可以与聚合函数一起使用 count(disctinct qty) 为2

 

4、Having 子句

(1)指定一个谓语来塞选组,而不是塞选行,行塞选发生在where,只塞选True的

(2)having 发生在group by 之后,可以再逻辑表达式中使用聚集函数、注意这里聚集是group by 之后每一组的数据

 

5、select 子句

(1)select 子句用于指定要返回到查询结果中属性列

(2)当使用了类似year(orderdate)这样的表达式的时候,如果没有指定别名,目标属性将没有名称,T-SQL 运行返回没有名称的结果列,但是关系模型不允许

(3)别名的格式有 AS 子句(推荐使用)、T-Sql 还支持<expression> <alias>、<alias>=<expression> 两种形式

(4)一个bug: 当select 子句的两个列名称的逗号掉了,T-sql 不会报错,只会将后者当成前者的别名

(5)注意select 是在 from 、where 、group by 、having 之后执行的,所以select 子句中的别名,不能出现在前面这些子句中

-- 解决方案是在select 和 where 中重复执行相同的表达式
select orderid , year(orderdate) as orderyear
from Sales.Orders
where year(orderdate) > 2006

--对于相同的表达式,SqlServer 会自动优化,只执行一次

 

 

 

(6)select * 是不好的编程做法、只有极少数例外,建议显式指定所需的关系列表

(7)但是select * 所增加的额外性能开销是微不足道的

 

6、order by子句

(1)标准sql 中,把orderby 子句的结果称为游标

(2)T-sql 允许使用序号位置指定排序列,但不建议使用,这是一种糟糕的编程方式

order by empid ,orderyear
等价于
order by 1,2

 

(3)T-sql 中允许在order by 子句中指定未出现在select 子句中的元素、这意味着可以按非输出列排序

(4)如果select 中指定了distinct ,则ordery by列表只能是输出列,因为distinct 后、单个结果行、背后有多个源行,导致不清晰

 

 

7、top

(1) top 不是标准SQL ,可用于赛选放回行数、或baifenbi

(2) 使用top ,不强制使用order by,如果没有使用orderby 按物理访问顺序返回

(3)top 在order by之后计算,也就是如果select 中制定了distinct

(4) top (1) percent 用于限定百分比,如前就是放回1% 的结果、百分比算出的行数如果不是整数、向上取整

(5) select top (5) with ties  表式按ordey by 排序输出前5位,如果最后一名有重复,把重复的也输出出来

(6)top 不支持跳过,必须从第1行开始输出。

 

8、offset - fetch

(1)offset - fetch 是标准Sql

(2)使用

跳过前50行、赛选后面的25行

select orderid , orderdate
from Sales.Orders
order by orderdate, orderid
offset 50 rows fetch next 25 rows only

 

(3)offset-fetch ,不能少offset,如果土跳过任何行,则使用offset 0 rows

(4)offset-fecth,  可以缺省fecth ,此时表示跳过指定行、获取后面所有的

 

 

9、case表达式

(1)标量表达式,可以在任何允许使用标量表达式的地方使用、如select 、where 、having 、order by 、check

(2)case是表达式,不是语句,不允许控制活动流、或做基于条件逻辑的操作

(3)如果Case 表达式没有ELSE 子句, 则默认为 ELSE NULL(返回NULL)

select productid ,productname ,categoryid,
case categoryid
  when 1 then 'Beverages'
  when 2 then 'Condiments'
  when 3 then 'Dairy Products'
  else 'unkonw category'
end
as categoryname
from Production.Products;

 

(3)case 有简单格式、和搜索格式,上面是简单格式,case 简单格式在case 关键字后面具有单个测试值或表达式、与when 子句的可能值进行较,返回then后面的输出值

(4)上述使用中,除非类别集合非常小、并且是静态的不会改变、否则最好的设计时在表中去维护产品类别,连表查询,这里只是为了在这里演示case 的用法才这么写

(5)case搜索格式比简单格式更加灵活、允许在when 子句中指定谓语、逻辑表达式,而不限于等值比较,case 表达式返回一个when逻辑表达式计算结果为true的相关联then子句中的值,如果没有true的表达式,返回Else

select orderid, custid ,val,
case 
  when val < 1000.00 then 'less then 1000'
  when val between 1000 and 3000 then 'between 1000 and 3000'
  when val >3000 then 'more then 3000'
  else 'unknow'
end
as valuecategory
from Sales.OrderValues;

 

(6)每一个简单格式可以转换成搜索格式,但反过来不一定

(7)T-sql支持的某些函数,其实可以将其看做case 表达式的缩写,如isnull(col1,'')接收两个参数,col1不是null 就输出col1 ,如果col1是null就输出空字符串

 

 

10、NULL标记

(1)T-sql使用三值逻辑、TRUE 、FALSE 、UNKNOWN

  (2) 理解 NULL 和 UNKNOWN , 表达式salary >0 ,当 salary =1000,返回true ;当salary=-1000 ,返回false ;当 salary = null,返回unknown

  (3)   sql 不同语言元素对unknown的处理方式不同,如对于所有查询赛选 where 、having 选择 “接收true”,意味着false和unknown 会被赛选掉、对于check约束而言,选择“拒绝false” ,那么true 和 unknown 会被接受

(4)如果直接使用二值逻辑,就不会有“接受true” 和 “拒绝false”的区别了

(5)NULL = NULL 的值是UNKNOWN,原因来自一个sql推理,NULL 表示缺失或未知值,不能说等于一个值,因此sql 提供了is null 和 is not null ,  这样才能返回false 、true,使用 = 、<> 仍然返回unknown

  (6)  在比较和排序的不同语言元素中,对null的处理方式也不同,如group by 子句将所有null 标记分成一组,认为NULL 是相等的、跟排列现值一样

(7)标准SQL将null 标记在现值之前排序,还是在现值排序之后留给产品实施、而T-sql 是在现值之前对null 排序

(8)为了强制执行unique约束、 标准sql 将null 标记视为彼此不同的,但是T-sql 中,NULL值是相同的,如果某列使用了UNIQUE 约束,那么只能有一个null

  (9)  由于sql 对unknown 和 null 标记的不一致处理、所以写sql 的时候要清晰地思考查询中null标记的三值逻辑

 

11、同时操作(all-at-once operations)

(1) 同时操作理解: 出现在同一逻辑处理阶段的所有表达式在同一时间点进行逻辑计算

(2) select 子句中不能引用同一select 子句中指定的列别名,及时被引用的子句在前面,就是因为select 这一逻辑处理阶段里面的所有表达式是同时进行逻辑计算

(3) where 中违背同时操作的经典案例

select col1 ,col2
from dbo.T1
where col1<>0 and col2/col2>2

 

很可能错误的认为where 后面的表达式是从左往右计算的,以为 col1<>0 计算结果为false 会直接短路,所以不会导致除0错误,导致执行失败,但是Sql Server 不支持短路,基于标准sql 同时操作的概念、SQL server 可以按任意顺序自由处理where子句的计算顺序

解决方案:通过case实现短路处理

select col1,col2
from dbo.T1
where
  case
     when col1=0 then 'no' 
     when col2/col2 > 2 then 'yes'
     else 'no'
  end = 'yes'

 

posted @ 2019-04-05 20:11  dehigher  阅读(266)  评论(0编辑  收藏  举报