SQLServer_第4章 查询

时间:2022-10-15 04:46:36

4   查询和视图

  SELECT语句可以从一个或多个表中选取特定的行和列。因为查询和检索数据是数据库管理中最重要的功能,所以SELECT语句在SQL中是工作量最大的部分。

  SELECT语句的结果通常是生成另外一个表。在执行过程中系统根据用户的标准从数据库中选出匹配的行和列,并将结果放到临时的表中。在直接SQL中,它将结果显示在终端的显示屏上,或者将结果送到打印机或文件中。也可以结合其他SQL语句来将结果放到一个已知名称的表中。

  SELECT语句功能强大。它用来完成关系代数运算“选择”,也可以完成其他两种关系运算 “投影”和“连接”,还可以完成聚合计算并对数据进行排序。

1   SELECT语句的语法

SELECT 筛选条件

FROM  表名称

Where 搜索子句

Groupby 分组子句

Having    分组统计条件

Order by 排序子句 ASC/DESC

2   结果筛选条件

(1)    select *  from users

(2)  select  username,ownname  from users

(3)      消除结果中的重复行distinct子句

Select  distinct    *     from       users   

(4)   select   username as 用户名, 真名=ownname  from users

注意:as和=的用途是一致的,但是要注意顺序

(5)   计算列值

在计算列值的时候,可以使用的算术运算符有:+ - * / %

select username as 用户名,真名=ownname + '123' from users (这里的+是连接字符串的功能)

例子:

select  product_name as 产品名称,库存总额=product_price*product_store

from   product

(6)   限制结果集返回行数  top / percent 

select  top 5 username, ownname  from users

使用top限制其返回的行数,如果使用percent关键字,则返回结果集的n%行,如:select  top  5 percent username from users

(7) 替换查询结果中的数据

例子:/*替换结果中的数据*/

select stu_name as 姓名,stu_major as 专业,性别=

       case

       when stu_sex='1' then ''

       when stu_sex='0' then ''

       end

,等级=

       case

       when stu_total_credit is null then '尚未选课'

       else str(stu_total_credit)  /*要注意两个结果的数据类型保持一致*/

       end

from xs

where stu_major='计算机'

3        搜索子句

3.1 运算符

比较运算符

逻辑运算符

=

And

<

 

Or

>

 

Not

<=

 

>=

 

!=

 

<>

 

 

例子:

1)        select * from employees  where last_name = 'jones'

2)        select * from employees where salary > 50000

3)        select * from employees where last_name = 'jones' and first_name = 'davy'

4)        select * from employees where last_name = 'jones' or last_name = 'smith'

5)        select * from employees where not(branch_office = 'boston')

6)        select * from employees where (last_name = 'jones'and first_name = 'indiana')or (last_name = 'smith' and first_name = 'bessie')

3.2  NULL和三值逻辑

  首先,在进行NULL判断时需要特殊的语法。例如,如果用户需要显示所有年薪未知的职员的全部信息,用户可以使用如下SELECT语句:

  select * from employees where salary is null

  相反,如果用户需要所有已知年薪数据的职员的信息,你可以使用以下语句:

  select * from employees where salary is not null

NULL表示未知的值而不是说明是一个空值。对于SQL来说意味着这个值是未知的,而只要这个值为未知,就不能将其与其他值比较。所以SQL允许除了在true false之外还有第三种类型的真值,称之为“非确定”值。

3.3          Like模式匹配

Like谓词的运算对象是字符型/文本型/日期型数据,返回逻辑值true/false。通常使用like谓词进行模糊查询。

通配符

意义

%

任意长度的字符 0个或多个

_

任何单个字符

[]

某个范围内的单个字符

^

指定不属于某范围内的任何单个字符

注意:在SQL语句中,字符串使用’’括起来的。

例子:

select * from  xs where stu_major like '计算机'

select * from  xs where stu_name like '%'

select * from xs where stu_id like '00__[2-3]%'

如果要做通配符的字符包括 % _ [] ^,可使用关键字 escape

select * from xs where stu_name like '/_%' escape '/' ,其中/字符是可以任意指定的。

或者用中括号[]也可以,如:'[_ ]%'

又如,包含5%怎么表示:%5[%]% %5/%% escape’/’

注意:如何将-用于查找字符串,必须放在[]首位,如:[ - abc]

[ à  [[ ]

] à  ]

3.4  范围比较

3.4.1 in

select * from users  where ip in('202.202.037.088','211.083.215.241')

注意:in后面还可以接子查询

3.4.2 between … and…

select * from users where logincount between 50 and 400

3.5 Contains Freetext谓词

3.5.1 Contains

若需要在表中搜索指定的单词、短语或近义词等,可以使用Contains谓词。该谓词用于在表中搜索指定的字符串,可以是精确匹配、模糊匹配,也可以是加权匹配。

该谓词的使用,首先要给这个表建立全文索引。可以通过命令方式或企业管理器给表建立全文索引,但需要注意的是,每当表中数据发生变化时,都要启动增量填充或全部填充。

Contains谓词的语法格式:

Contains ({ columns |  *}, <contains_search_condition>)

contains_search_condition::=

{<simple_term : word | “phrase” >|<prefix_term >|<generation_term>|<proximity_term>|<weighted_term>} and |and not|or <contains_search_condition>

1.  simple_term

例子:在book表中查询字符串包含“语”的记录。

select * from book where contains(*,’’)

注意:contains(*,’’)中的*表示表中参与到全文索引中的所有列!

例子:在book表中查询含:“operation system”的书的情况:

Select * from book where contains(*,’ ” operation system” ‘)

2.  Prefix_term

给出了要搜索单词或短语必须匹配的前缀,{“word*”  |  “phase*”},当查询的是串是短语时,需要双引号定界。

例子:查询作者姓王的情况

Select * from book where contains(author,’*’)

例子:查询书名中包含“SQL Server”的情况

Select * from book where contains(title,’” SQL Server”’)

3.  Generation_term

搜索包含原词的派生词,如单复数,时态等,格式为:

Formsof(inflecational,<simple_term>[…n])

例子:查询含operate或其派生词的情况

Select * from book where contains*,’ormsof(inflecational,operate)’

4.  Proximity_term

搜索包含near或~运算符左右两边的词或短语,格式为:

{<simple_term> | <prefix_term>}{{near | ~ }{<simple_term> | <prefix_term>}}[….]

例子:查询在“程序”附近有“设计”字样的书

Select * from book where contains (*,’程序 near  设计’)

5Weight_term

查询的数据与给定的权重进行加权匹配,格式为:

Isabout({{<simple_term>|<prefix_term }|<generation_term>|<proximity_term>|<weighted_term>}  weightweight_value})

例子:

Select * from book where contains(*,isabout(operate weight(.4),system weight(.8)))

3.5.2 freetext

Freetext的查询精度没有contains高。该谓词对所查询的串也没有写法要求。

select * from book  where freetext (*,’程序 设计’)

本节示例表book表生成T-SQL语句:

create table book

(title char(30) not null

,author char(10) not null

,abstract ntext null

)

insert into book  values   ('计算机程序设计','王键','计算机程序设计基础教程')

insert into book  values   ('汇编语言','王不顺','IBMPC汇编程序设计')

insert into book  values   ('C++语言','黎明','C++程序语言设计')

3.6 子查询

子查询可以用在select语句中,也可以用在insert update delete 语句中。

子查询通常与in exist 或比较运算符结合使用:

3.6.1   notin子查询

select * from exam_user_log  where xsbh in (select distinct xsbh from exam_score)

select * from exam_user_log  where xsbh not in (select distinct xsbh from exam_score)

注意:in 子查询只能返回1列值,如果是较复杂的查询,可以使用嵌套的子查询。

例子:查询未选修离散数学的学生的情况:

Select * from xs

Where stu_id not in

(      select stu_id from xs_kc

       Where kc_id in

              (

                     Select  kc_id from  kc

                     Where kc_name=’离散数学

              )

)

3.6.2   比较子查询

格式:expession{<|<=|=|>|>=|!=|<>|!<|>!} {all|some|any} (子查询)

select *

from exam_user_log

where xsbh<>all(select distinct xsbh from exam_score)

例子:查找比所有计算机系的学生年龄都大的学生

Select * from xs

Where     stu_birth<all

       (select stu_birth from xs

       Where stu_major=’计算机

       )

例子:查找课程号为206且成绩不低于课程号为101的最低成绩的学生的学号。

Select stu_id from xs_kc

Where ks_id=’ 206’ and  kc_score!<any

       (

              Select kc_score from xs_kc

              Where ks_id=’ 101’

       )

3.6.3   notExists子查询

select *

from exam_user_log

where not exists (select distinct xsbh from exam_score where xsbh=exam_user_log.xsbh)

例子:查询选修了206号课程的所有学生姓名

Select stu_name from xs

Where exists

       (select  *  from xs_kc

     Where  stu_id=xs.stu_id and kc_id=’ 206’

       )

分析这种相关子查询的工作过程!

例子:查找选修了全部课程的同学的姓名

select name from xs

where not exists

(select *  from kc

where not exists

              (select *        from xs_kc

               where stuid=xs.stuid and subid=kc.subid

              )

)

 

4   from

from子句中可以查询的内容有:表,视图,行集函数,XML文档,子查询,连接表。

4.1 table_name

42 view

注意:可以使用as选项为表或视图指定别名。

4.3 rowset_function

Rowset_function是一个行集函数,通常返回一个表或视图。主要的行集函数有:

4.3.1 containstable函数

4.3.2 freetexttable函数

4.3.3 opendatasource函数

4.3.4 openquery函数

4.3.5 openrowset函数

4.3.6 openxml函数

4.4 derived_table

子查询必须使用一个别名

Select * from (select * from xs where stu_birth<'20070731') as m (学号,姓名,专业,性别,出生日期,学分,备注)

4.5 joined_table

5   连接

连接查询有两大类表示形式,一个是符合SQL标准连接谓词表示形式,一个是SQL扩展的使用关键字JOIN的表示形式。

5.1 连接谓词

例子:查询每个学生的情况及其选课的情况

select xs.*,xs_kc.*      from xs,xs_kc      where xs.stu_id=xs_kc.stu_id

例子:

/*查询选修了课程号为101,且成绩在60分以上的学生姓名和成绩。*/

select stu_name,score  from xs,xs_kc

where xs.stu_id=xs_kc.stu_id and xs_kc.kc_id='101' and xs_kc.score>=60

例子:多表连接

/*查找选修了计算机基础课程并且成绩在60上的学生学号 姓名 课程名 及成绩*/

select xs.stu_id as 学号,xs.stu_name as 姓名 ,kc.kc_name as 课程名称, xs_kc.score as 成绩

from xs,kc,xs_kc

where xs.stu_id=xs_kc.stu_id and kc.kc_id=xs_kc.kc_id and kc.kc_name='计算机基础' and xs_kc.score>=60

注意:

1)  两个字段必须是可比的;

2)  比较符不一定是=,也可以是其他的,如 >  <  等;但是当用=时,就是等值连接。若在目标列中去除相同的字段名,就是自然连接。

3)  连接和子查询的区别:连接可以合并两个或多个表中的数据,而带子查询的select语句的结果只能来自一个表。

4)  有的查询既可以使用连接,也可以使用子查询来表达。通常使用子查询表示可以将一个复杂的查询分解为一系列的逻辑步骤,条理清晰,而使用连接表示有执行速度快的优点。

5.2      join关键字指定的连接

5.2.1 内连接

例子:

/*查询每个学生的情况及其选课的情况*/

select *   from xs inner join xs_kc  on xs.stuid=xs_kc.stu_id

inner可以省略,因为SQL中默认的就是内连接

例子: 两表内连接

/*查询选修了课程号为101,且成绩在60分以上的学生姓名和成绩。*/

select xs.stu_name,xs_kc.score from xs inner join xs_kc on xs.stu_id=xs_kc.stu_id

where xs_kc.kc_id='101' and xs_kc.score>=60

例子:多表内连接

/*查找选修了计算机基础课程并且成绩在60上的学生学号 姓名 课程名 及成绩*/

select xs.stu_id as 学号,xs.stu_name as 姓名,kc.kc_name as 课程名称,xs_kc.score as 成绩

from xs inner join xs_kc join kc  on kc.kc_id=xs_kc.kc_id  on xs.stu_id=xs_kc.stu_id

where kc.kc_name='计算机基础' and xs_kc.score>=60

注意:若将on kc.kc_id=xs_kc.kc_id  on xs.stu_id=xs_kc.stu_id两个连接条件写反,则报错!

这种多表连接的时候,通常是从内到外进行连接.一定要注意!

例子:自连接

/*查找不同课程成绩相同的学号,课程号 成绩*/

select a.stu_id,a.kc_id,a.score

from xs_kc a inner join xs_kc b on a.stu_id=b.stu_id and a.score =b.score and a.kc_id !=b.kc_id

5.2.2          外连接

注意:外连接只能对两个表进行。

1)  左外连接 left join

例子:/*查找所有学生的选修课程号,若没有选修课程,也要包括其情况*/

select xs.*,xs_kc.kc_id

from xs left outer join xs_kc on xs.stu_id=xs_kc.stu_id

2)  右外连接  right join

例子:/*查找被选修了的课程的选修情况和所有开设的课程*/

select kc.* ,xs_kc.stu_id

from  xs_kc right join kc  on kc.kc_id=xs_kc.kc_id

备注:本质上 左右外连接并没有区别,只是在使用的时候注意顺序就可以了。

3)  完全外连接  full join

5.2.3 交叉连接cross join

交叉连接实际上是将两个表进行笛卡尔积运算。注意:交叉连接不能有条件,且不能带where子句。

例子:列出学生所有可能的选课情况

select  学号,姓名,课程号,课程名 from xs cross join ks

6   排序

如果你希望以字母表顺序将结果列出又该怎么做呢?只要使用ORDER BY子句就可以按照升序或降序来排列结果:

select distinct branch_office  from employees  order by branch_office asc

ORDER BY子句只将临时表中的结果进行排序;并不影响原来的表。

7 数据汇总

7.1      聚合函数

    常用聚合函数表

函数

 返回值

Sum(col_name)

返回一系列值的总和

Avg(col_name)

返回一系列值的平均值

COUNT(*)      Count_big  返回bigint型!

其功能是检索表中满足给定条件的记录数

Max(col_name)

返回一系列值中的最大值

Min(col_name)

返回一系列值中的最小值

例子:select count(distinct stu_id) as '已选课学生总数' from  xs_kc

例子:select count(*) as '已选课总人次数' from xs_kc

例子:/*101课程的平均成绩*/

select avg(score) as '101课程的平均成绩' from xs_kc

where xs_kc.kc_id='101'

4.2      groupby子句

例子:/*将各专业及其学生总数输出*/

select stu_major as '专业名',count(stu_major) as '该专业学生总数'

from xs

group by stu_major

例子:/*求被选修的各门课程的平均成绩和选修该课程的人数*/

select kc_id,avg(score) as '平均成绩',count(stu_id) as '选修人数'

from xs_kc

group by kc_id

例子:查询出每个专业的男女生总人数和总学生数

select stu_major as '专业名',stu_sex,count(stu_major) as '该专业学生总数'

from xs

group by stu_major,stu_sex

with rollup

注意:多于1列的分组是按照group by列的逆序排列。

备注:with cube 除了进行rollup的汇总外,还会对一切可能的组合进行统计汇总。

4.3 having子句

使用group by 子句和聚合函数对数据进行分组后,还可以使用having字句对分组的数据进一步筛选。

例子:/*查找选修课程超过两们且成绩都在80分以上的学生的学号*/

select stu_id from xs_kc

where score>=80

group by stu_id

having count(kc_id)>=2

注意:groupby子句是对where的结果进行分组,而having则是对groupby以后的分组数据进行过滤。

4.4 compute子句

compute子句用于分类汇总。Compute将产生额外的汇总行,其格式是:

compute 聚合函数名称(expression)

例子:/*查询通信专业学生的学号、姓名、出生时间,并产生一个学生总人数的行*/

select stu_id,stu_name,stu_birth from xs

where stu_major like '%通信%'

compute count(stu_id)

8   其他子句

8.1 into子句

使用into子句可以将查询结果保存到一个新建的表中。

select *

into temp1

from exam_user_log

8.2 union子句

UNION 运算符使您得以将两个或多个 SELECT 语句的结果组合成一个结果集。使用 UNION 组合的结果集都必须具有相同的结构。而且它们的列数必须相同,并且相应的结果集列的数据类型必须兼容。

UNION 的指定方式如下:

select_statement UNION [ALL] select_statement

例如,Table1 Table2 具有相同的两列结构。

Table1

 

Table2

 

ColumnA

ColumnB

ColumnC

ColumnD

char(4)

int

char(4)

int

abc

1

ghi

3

def

2

jkl

4

ghi

3

mno

5

下面的查询在这两个表之间创建 UNION 运算:

SELECT * FROM Table1

UNION

SELECT * FROM Table2

下面是结果集:

ColumnA  ColumnB

-------  --------

abc      1

def      2

ghi      3

jkl      4

mno      5

默认情况下,UNION 运算符从结果集中删除重复的行。如果使用 ALL 关键字,那么结果中将包含所有行并且将不删除重复的行。

9  视图

9.1 视图的优点

1.         为用户集中数据,简化用户的数据查询和处理;

2.         屏蔽数据库的复杂性;

3.         简化用户权限的管理;

4.         便于数据共享;

5.         可以重新组织数据以便输出到其他应用程序中。

使用视图时,要注意:

1.         不能把规则、默认值、触发器与视图相关联;

2.         不能在视图上建立任何索引,包括全文索引。

9.2 使用企业管理器或向导创建视图

9.3 使用命令创建视图

Create view view_name

As

       Select sententce

Go

例子:

Create view view_name

As

       Select * from xs where stu_major=’计算机

Go

注意:创建视图语句必须是批查询中的第一条语句。

Create view 语句的完整格式:

Create view database_name.owner_name.view_name(column_name1,column_name2,….)

With <view_attribute>[1…n]

As  select statement

With check option /*指出在视图上所进行的修改都要符合select statement */

其中,view_attribute可以取以下值:

1encryption  系统在系统表syscomments中存储create view语句时进行加密;

2schemabinding 说明视图与其所依赖的表或视图结构相关联。

3view_metadata 指定为引用视图的查询请求浏览模式的元数据时,向DBLIBODBCOLEDB API返回有关视图的元数据信息,而不是返回给基表或其他表。

例子:

/*创建cs_kc视图,包括计算机系各学生的信息及其选课的课程号和成绩*/

create view cs_kc

as

       select xs.*,xs_kc.kc_id,xs_kc.score

       from xs,xs_kc

       where xs.stu_id=xs_kc.stu_id and  xs.stu_major='计算机'

with check option

create view cs_kc

as

       select xs.*,xs_kc.kc_id,xs_kc.score

       from xs left join xs_kc on xs.stu_id=xs_kc.stu_id

       where xs.stu_major='计算机'

with check option

例子:

/*创建计算机专业学生的平均成绩,包含学号和平均成绩*/

create view cs_kc_avg(num,score_avg)

as

       select stu_id,avg(score)

       from cs_kc

       group by stu_id

9.4 查询视图

9.5 更新视图

只有是可更新的视图才能被更新,可更新的视图通常包括:

9.5.1 可更新的视图

1)所有的数据至少包含从一个基本表得到的原数据(没有用聚合函数、toppercentdistinct等语句)

2)可更新的分区视图

3)通过instead of 触发器创建的可更新视图

9.5.2 插入和删除数据

插入数据可以使用 insert into view_name values(…..)语句来完成。但是其中的限制比较多,如:

该视图的数据只能来自于1个基本表,或是可更新的分区视图;

删除数据可以使用delete from view_name where ….,其中的限制如同插入。

9.5.3   修改数据

该语句可以通过视图修改基本表的数据。若一个视图(非分区视图)依赖多个表,则一次修改该视图只能变动一个基本表的数据。

9.6 修改视图的定义

Alter view view_name

As

      Select statement

….

9.7 删除视图

Drop  view view_name