SELECT语句的使用
select 语句:
○5 SELECT select_list
○1 FROM table_source
○2 [ WHERE search_condition ]
○3 [ GROUP BY group_by_expression]
○4 [ HAVING search_condition ]
○6 [ ORDER BY order_expresion [ASC |DESC ] ]
SELECT语句执行顺序:
A、FROM阶段
B、WHERE阶段
C、GROUPBY阶段
D、HAVING阶段
E、SELECT阶段
F、ORDERBY阶段
1)、FROM阶段:
FROM 阶段标识出查询的来源表,并处理表运算符如果指定了表运算符,还需 要按从左到右的顺序,对运算符进行逐个处理。
表运算符有4 类,JOIN、APPLY、PIVOT、UNPIVOT。
在涉及到联接运算的查询中(各种join),主要有以下几个步骤:
a. 求笛卡尔积。不论是什么类型的联接运算,首先都是执行交叉连接(cross join),得出最大的可能结果集。如果左表有n 行,右表有m行,则结果集有n x m 行,求笛卡儿积,生成虚拟表VT1-J1。
b. ON 筛选器。这个阶段对上个步骤生成的VT1-J1 进行筛选,根据ON 子句中出现的谓词进行筛选,让谓词取值为true 的行通过了考验,插入到VT1-J2。
c. 对于外联接(left,right,full outer join),还需要添加外部行。在上个步骤中,ON 条件剔除掉了所有不匹配两张表的行。但是在外联接中,通过指定外连接的类型,需要将其
中的一个或者两个表标记为保留表,并返回该表中所有的行。所以这时候还需要将保留
表中被ON 筛选条件剔除的行重新加入到结果集中(这些重新加进来的表,书中称为外
部行),并将外部行中非保留表的列值标记为NULL,生成VT1-J3。这一个步骤,只
有外联接才执行,对于内联接(inner join)只需要执行a 和b 两个步骤的。
概括地讲,FROM 阶段就是进行预处理的,根据提供的运算符对语句中提到的各个表进行处理(除了join,还有apply,pivot,unpivot)
2)、WHERE 阶段:
WHERE 阶段是根据<where_predicate>中条件对VT1 中的行进行筛选,让条件成立的行才会插入到VT2 中。此时,因为还没有对数据进行分组,所以在where 子句中不能聚合。也不能引用select 列表中创建的别名,因为SELECT 阶段还在后面。
另外,对于包含JOIN 的查询,到底ON 和WHERE 子句有什么区别,应该什么时候使用ON子句,什么时候使用where 子句?只有对于外联接,ON 和where 子句才会存在这种逻辑区别,因为在外联接中,通过ON 子句的筛选之后,还要对保留表进行外部行添加,而where 子句则是在外部行添加过之后才进行筛选的。因此,ON 子句对这种外联接的情况的筛选,并不是最终的结果,在FROM 阶段的第三个步骤,还会把外部行添加回来的。而对于内联接,where子句和on 子句作用是完全一样的,在哪里筛选都是同种效果,没有其他步骤。所以在处理这种含有外联接的查询,一定要注意ON 筛选和where 筛选的区别,避免使用错了,达不到筛选的效果。另外,对于内联接,一个不错的建议是,对于两个表都存在的字段筛选,用ON 子句,对于单个表的字段筛选,用where,例如:select * from a inner join b on a.col = b.col where a.col2>1。
3)、GROUP BY阶段
GROUP 阶段按照指定的列名列表,将VT2中的行进行分组,生成VT3。最后每个
分组只有一行。
4)、HAVING 阶段
该阶段根据HAVING 子句中出现的谓词对VT3 的分组进行筛选,并将符合条件的组插入到VT4中。HAVING 筛选器是唯一能筛选分组数据的筛选器,ON 和where 都不行。理由很简单,ON 和where 都是在分组之前进行处理的,自然不能对分组进行筛选. 所以HAVING 和WHERE 的区别,也是很显而易见了。HAVING 只能与 SELECT 语句一起使用。HAVING 通常在 GROUP BY 子句中使用。如果不使用 GROUP BY 子句,则HAVING 的行为与WHERE子句一样。
5)、SELECT阶段
这个阶段是投影的过程,处理SELECT 子句提到的元素,产生VT5。这个步骤一般按下列顺序进行:
a. 计算SELECT 列表中的表达式,生成VT5-1。
b. 若有DISTINCT,则删除VT5-1 中的重复行,生成VT5-2
c. 若有TOP,则根据ORDER BY子句定义的逻辑顺序,从VT5-2 中选择签名指定
数量或者百分比的行,生成VT5-3
6)、ORDER BY阶段
根据ORDER BY子句中指定的列明列表,对VT5-3 中的行,进行排序,生成游标VC6.
集合和游标:
SQL 的理论基础是集合,集合是无序的,它只是成员的一种逻辑集合。对于带有排序作用的ORDER BY子句的查询,可以返回一个对象,其中的行按照特定的顺序组织在一起。ANSI 把这种对象成为游标(cursor)。因为在这一步中,最后返回的是游标,所以带有order by 的查询,是不能用来定义视图,子查询,公用表等。例如:
SELECT * FROM (SELECT col1,col2 FROM tab_test ORDER BY col1)是无效的,并且将报错。当然SQL SERVER 在实际的查询过程中,有查询优化器来生成实际的工作计划。以何种顺序来访问表,使用什么方法和索引,应用哪种联接方法,都是由查询优化器来决定的。
变量:
变量对于一种语言来说是必不可少的组成部分。
变量的作用:
§ 作为计数器计算循环执行的次数或控制循环执行的次数。
§ 保存数据值以供控制流语句测试。
§ 保存存储过程返回代码要返回的数据值或函数返回值。
§ SQL SERVER 2008 可以在定义变量时立即赋值
Transact-SQL 语言允许使用两种变量:
一种是用户自己定义的局部变量(LocalVariable),
另一种是系统提供的全局变量(GlobalVariable)。
1)、局部变量:
局部变量使用户自己定义的变量,它的作用范围近在程序内部。通常只能在一个批处理中或存储过程中使用,用来存储从表中查询到的数据,或当作程序执行过程中暂存变量使用,局部变量使用DECLARE 语句定义,并且指定变量的数据类型,然后可以使用SET或SELECT 语句为变量初始化;
局部变量必须以“@”开头,而且必须先声明后使用。形如:@S1
其声明格式如下:
DECLARE @变量名变量类型[,@变量名变量类型]
SELECT @局部变量=变量值附值
SET @局部变量=变量值附值
例:在Demo_DB 数据库中TimeRecords 表中用名为@emp 的局部变量检索所有以P11034
开头的emp_id 打卡信息,代码如下:
declare@emp varchar(20)
select@emp = ‘p110343%‘
select* from TimeRecords
whereemp_id like @emp
执行结果:
Id clock_id emp_id join_id depart_id card_id
2385 105 P1103432 12443 01101003 2852036222
2539 105 P1103432 12443 01101003 2852036222
4573 105 P1103432 12443 01101003 2852036222
5557 102 P1103436 12447 01100502 2619730638
注意:如果声明字符型的局部变量,一定要在变量类型中指明其最大长度,否则系统认为其长度为1。
Select 与set 比较:
l select 功能强大一点,可以一次对多个变量同时赋值;
l 当源操作数不为空时,目的操作数都等于源操作数(二者此时是一样的)
l 当源操作数为空(NULL)时,用set 时,目的操作数为空,用select 时,目的操作数不改变。
declare@s1 varchar(10),@s2varchar(10) ,@s3 varchar(10)
set @s1=10
set @s2=10
set @s3=10
declare@s1 varchar(10),@s2varchar(10) ,@s3 varchar(10)
select@s1=‘10‘, @s2= ‘10‘, @s3= ‘10‘
2)、全局变量:
全局变量是SQL Server 系统内部使用的变量,起作用范围并不局限于某一程序,而是任何程序均可随时调用。全局变量通常存储一些SQL Server 的配置设置值和效能统计数据。用户可在程序中用全局变量来测试系统的设定值或者Transact_SQL命令执行后的状态值。
引用全局变量时,全局变量的名字前面要有两个标记符“@@”。不能定义与全局变量同名的局部变量.形如:@@s1。
全局变量及其功能:
全局变量 功 能
@@CONNECTIONS自SQL Server 最近一次启动以来登录或试图登录的次数
@@CPU_BUSY自SQL Server 最近一次启动以来CPU Server 的工作时间
@@CURRSOR_ROWS返回在本次连接最新打开的游标中的行数
@@DATEFIRST返回SETDATEFIRST 参数的当前值
@@DBTS数据库的惟一时间标记值
@@ERROR系统生成的最后一个错误,若为0 则成功
@@FETCH_STATUS最近一条FETCH 语句的标志
@@IDENTITY保存最近一次的插入身份值
@@IDLE自CPU 服务器最近一次启动以来的累计空闲时间
@@IO_BUSY服务器输入输出操作的累计时间
@@LANGID当前使用的语言的ID
@@LANGUAGE当前使用语言的名称
@@LOCK_TIMEOUT返回当前锁的超时设置
@@MAX_CONNECTIONS同时与SQL Server 相连的最大连接数量
@@MAX_PRECISION十进制与数据类型的精度级别
@@NESTLEVEL当前调用存储过程的嵌套级,范围为0~16
@@OPTIONS返回当前SET 选项的信息
@@PACK_RECEIVED所读的输入包数量
@@PACKET_SENT所写的输出包数量
@@PACKET_ERRORS读与写数据包的错误数
@@RPOCID当前存储过程的ID
@@REMSERVER返回远程数据库的名称
@@ROWCOUNT最近一次查询涉及的行数
@@SERVERNAME本地服务器名称
@@SERVICENAME当前运行的服务器名称
@@SPID当前进程的ID
@@TEXTSIZE当前最大的文本或图像数据大小
@@TIMETICKS每一个独立的计算机报时信号的间隔(ms)数,报时信号为31.25ms 或1/32s
@@TOTAL_ERRORS读写过程中的错误数量
@@TOTAL_READ读磁盘次数(不是高速缓存)
@@TOTAL_WRITE写磁盘次数
@@TRANCOUNT当前用户的活动事务处理总数
@@VERSION当前SQL Server 的版本号
本文出自 “Ricky's Blog” 博客,请务必保留此出处http://57388.blog.51cto.com/47388/1626965
25. SQL -- TSQL(SELECT语句的使用,子查询,连接,通配符 )(1)
原文地址:http://57388.blog.51cto.com/47388/1626965