1.sql组成
SQL 是最有影响力的商用市场化的关系查询语言。SQL 语言包括几个部分:
数据定义语言(DDL)
,它提供了定义关系模式、删除关系以及修改关系模式的命令。
数据操纵语言(DML)
,它包括查询语言,以及往数据库中插入元组、从数据库中删除元组和修改数据库中元组的命令。
同时还包括 DCL(数据控制语言) 和 TCL(事务控制语言)
2. select from where 语句
select 子句用于列出查询结果中所需要的属性。
from 子句是一个查询求值中需要访问的关系列表。
Where 子句是一个作用在 from 子句中关系的属性上的谓词。
一个典型的sql查询具有如下形式:
每个 Ai 代表一个属性,每个 ri代表一个关系。p是一个谓词。如果省略 where 子句,则谓词 p为true。
举例
注意 dept_name 属性既出现在 instructor 关系中,也出
现在 department 中,关系名被用作前缀(在 instructor. dept_
name 和 department. dept_name 中)来说明我们使用的是哪个
属性。相反,属性 name 和 puilding 只出现在一个关系中,
因而不需要把关系名作为前缀。
运算顺序
尽管各子句必须以 select 、from 、where 的次序写出, 但理解查询所代表运算的最容易的方式是以
运算的顺序来考察各子句:首先是 from,然后是 where,最后是 select
可以通过下面的迭代过程来理解,此过程可为 from 子句的结果关系产生元组。
此结果关系具有来自 from 子句中所有关系的所有属性。由于在关系ri和rj中可能出现相同的属性名,正如举例中所看到的,我们在属性名前加上关系名作为前缀,表示该属性来自于哪个关系。
从from语句会构造多个关系的笛卡尔积,这会导致数据可能非常庞大,不是我们需要的。此时where 子句中的谓词用来限制笛卡儿积所建立的组合
理解
通常说来,一个 SQL 查询的含义可以理解如下 :
-
为 from 子句中列出的关系产生笛卡儿积。
-
在步骤 1 的结果上应用 where 子句中指定的谓词。
-
对于步骤 2 结果中的每个元组,输出 select 子句中指定的属性(或表达式的结果) 。
3. join.…using
natural join(自然连接)自动匹配所有同名列,这可能导致未知的错误。可以使用join … using …指定匹配的属性
考虑运算 r1 join r2 using( A1 , A2) 。它与 r1与 r2的自然连接类似, 只不过在t1.A1=t2.A1并且t1.A2=t2.A2成立的前提下,来自r1的元组t1和来自r2 的元组t2就能匹配,即使 r1与 r2的都具有名为A3的属性,也不需要t1.A3=t2.A3
SELECT name, title
FROM (instructor NATURAL JOIN teaches) JOIN course USING (course_id);
解析
分步执行:
(instructor NATURAL JOIN teaches) 先执行,自动匹配它们的公共列(如 ID)。
显式地 用 JOIN course USING (course_id) 连接 course 表,保证 course_id 作为连接条件。
相较于natural join,通常建议使用 JOIN … USING 以确保连接的可控性和可读性。
4.一些基本运算
更名运算as
Select name as instructor_name ,course_id
from instructor ,teaches Where instructor. id = teaches. id;
as 子句在重命名关系时特别有用。重命名关系的一个原因是把一个长的关系名换成短的,这样在查询的其他地方使用起来就更为方便。例如,我们重写查询" 对于大学中所有讲授课程的教师,找出他们的姓名以及所讲述的所有课程标识”:
Select T.name ,S. course_id
from instructor as T,teaches as S
where T.id= S. id;
重命名关系的另一个原因是为了适用于需要比较同一个关系中的元组的情况。为此我们需要把一个关系跟它自身进行笛卡儿积运算,如果不重命名的话,就不可能把一个元组与其他元组区分开来假设我们希望写出查询:“找出满足下面条件的所有教师的姓名,他们的工资至少比 Biology 系某一个教师的工资要高”,我们可以写出这样的 SQL 表达式:
select distinct T. namme
from instructor as T,instructor as S Where T.salary > S. salary and S. dept_name = ”Biology ;
字符串
SQL 使用一对单引号来标示字符串,例如’Computer’ 。如果单引号是字符串的组成部分,那就用两个单引号字符来表示,如字符串“it’s right "可表示为“it"s right”。
在 SQL 标准中,字符串上的相等运算是大小写敏感的,所以表达式” comp. sci “= "Comp. Sci ”的结果是假。然而一些数据库系统,如 MySQL 和 SQL Server,在匹配字符串时并不区分大小写,所以在这些数据库中”comp. sci. = "Comp. Sci. ”的结果可能是真。然而这种默认方式是可以在数据库级或特定属性级被修改的。
SQL 还允许在字符串上有多种函数,例如串联(使用”|| ” ) 、提取子串、计算字符串长度、大小写转换(用 upper(s )将字符串 转换为大写或用lower(s)将字符串 转换为小写) 、去掉字符串后面的空格(使用 trim(s) ) ,等等。不同数据库系统所提供的字符串函数集是不同的
在字符串上可以使用 like 操作符来实现模式匹配。我们使用两个特殊的字符来描述模式 :
百分号(% ) : 匹配任意子串。
下划线(_) : 匹配任意一个字符。
模式是大小写敏感的,也就是说,大写字符与小写字符不匹配,反之亦然。为了说明模式匹配,考虑下列例子:
“Intro% "匹配任何以“Intro" 打头的字符串。
“% Comp% 匹配任何包含“Comp”子串的字 符串,例如“Itro. to Computer Science ”和
“Computational Biology " 。
“___ “匹配只含三个字符的字符串。
“___% 匹配至少含三个字符的字符串。
在 SQL 中用比较运算符 like 来表达模式。考虑查询“找出所在建筑名称中包含子串"Watson 的所
有系名”,该查询的写法如下 :
Select dept_name from department
Where building like“% Watson %”;
为使模式中能够包含特殊模式的字符(即% 和_) ,SQL 人允许定义转义字符。转义字符直接放在特殊字符的前面,表示该特殊字符被当成普通字符。我们在 like 比较运算中使用 escape 关键词
来定义转义字符。为了说明这一用法,考虑以下模式,它使用反斜线(\ )作为转义字符
:
like 'ab\% cd% 'escape'\' : 匹配所有以“ab%cd" 开头的字符串
like 'ab\\cd% ' escape'\' : 匹配所有以“ab\cd"开头的字符串。
星号
星号*
可以用在 select 子句中表示“所有的属性”,因而,如下查询的 select 子句中使用
Select imstruclor.* from istructor ,teaches Where instructor. ID = leaches. ID;
表示 instructor 中的所有属性都被选中
显示次序
SQL 为用户提供了一些对关系中元组显示次序的控制。order by 子句就可以让查询结果中元组按排列顺序显示。为了按字母顺序列出在 Physics 系的所有教师,我们可以这样写:
Select name from instruclor Where dept_name = “Physics” order by name ;
order by 子句默认使用升序
。要说明排序顺序,我们可以用 desc 表示降序
,或者用 asc 表示升序
.此外,排序可在多个属性上进行。假设我们希望按 salary 的降序列出整个 instructor 关系。如果有几位教师的工资相同,就将它们按姓名升序排列。我们用 SQL 将该查询表示如下 :
Select from instructor order by salary desc,name asc;
where 子句谓词
1.使用between…and…
为了简化 where 子句,SQL 提供 between 比较运算符来说明一个值是小于或等于某个值,同时大于或等于另一个值的。类似地,我们还可以使用 not between 比较运算符。
2.使用and连接添加条件
3.SQL 人允许我们用记号(v1,…,vm)来表示一个分量值分别为v1到vm的m维元组。在元组上可以使用比较运算符按照字典顺序进行比较上可以运用比较运算符, 按字典顺序进行比较运算。 例如 ,
(a1 ,a2) <=(b1,b2)在a1 <=b1 且 a2 <=b2时为真。类似地,当两个元组在所有属性上相等时,它们是相等的。
Select name ,course_id
from instructor ,teaches
Where (instructor. ID,dept_name) = (teaches. ID, 'Biology') ;
集合运算
并运算
为了找出在 2009 年秋季开课,或者在 2010 年春季开课或两个学期都开课的所有课程,我们可写
查询语句 :
与 select 子名不同,union 运算自动去除重复。
如果我们想保留所有重复,就必须用 union all 代替 union :
交运算
为了找出在 2009 年秋季和 2010 年春季同时开课的所有课程的集合,我们可写出:
intersect 运算自动去除重复
如果我们想保留所有重复 ,就必须用 intersect all 代替 intersect :
差运算
为了找出在 2009 年秋季学期开课但不在 2010 年春季学期开课的所有课程,我们可写出:
except 运算从其第一个输入中输出所有不出现在第二个输入中的元组,也即它执行集差操作。此运算在执行集差操作之前自动去除输入中的重复
如果我们想保留所有重复 ,就必须用 except all 代替 except:
聚集函数
聚集函数是以值的一个集合(集或多重集 ) 为输入、返回单个值的函数。SQL 提供了五个固有桶集果数:
sum 和 avg 的输入必须是数字集,但其他运算符还可作用在非数字数据类型的集合上 ,如字符串。
分组聚集
有时候我们不仅希望将聚集函数作用在单个元组集上,而且也和希望将其作用到一组元组集上; 在SQL 中可用 group by 子句实现这个愿望。group by 子句中给出的一个或多个属性是用来构造分组的。在 group by 子句中的所有属性上取值相同的元组将被分在一个组中。
考虑查询“找出每个系的平均工资" :
having语句
有时候,对分组限定条件比对元组限定条件更有用。例如,我们也许只对教师平均工资超过42 000美元的系感兴趣。该条件并不针对单个元组,而是针对 group by 子句构成的分组。为表达这样的查询,我们使用 SQL 的 having 子句。having 子句中的谓词在形成分组后才起作用,因此可以使用聚集函数
。我们用 SQL 表达该查询如下 :
与 select 子句的情况类似,任何出现在 having 子句中,但没有被聚集的属性必须出现在 group by 子句中,否则查询就被当成是错误的。
包含聚集、group by 或 having 子句的查询的含义可通过下述操作序列来定义:
-
与不带聚集的查询情况类似,最先根据 from 子句来计
算出一个关系。 -
如果出现了 where 子句,where 子句中的谓词将应用到 from 子名的结果关系上。
-
如果出现了 group by 子句,满足 where 谓词的元组通过 group by 子句形成分组。如果没有
group by 子句,满足 where 谓词的整个元组集被当作一个分组。 -
如果出现了 having 子句,它将应用到每个分组上; 不满足 having 子名谓词的分组将被抛弃。
-
select 子句利用剩下的分组产生出查询结果中的元组,即在每个分组上应用聚集函数来得到单
个结果元组。
对空值的聚集
空值的存在给聚集运算的处理带来了麻烦。例如,假设 instructor 关系中有些元组在 salary 上取空值。考虑以下计算所有工资总额的查询 :
由于一些元组在 salary 上取空值,上述查询待求和的值中就包含了空值。SQL 标准本身并不认为求和结果为null,而是认为 sum 运算符应忽略输入中的 null值。总而言之,聚集函数根据以下原则处理空值: 除了 count( *)外所有的聚集函数都忽略输入集合中的空值。由于空值被忽略,所以可能造成函数运算的输入值集合为空集。规定空集的 count 运算值为0,其他所有聚集运算在输入为空集的情况下返回一个空值。
数据库修改
删除
删除请求的表达与查询非常类似。我们只能删除整个元组,而不能只删除某些属性上的值。SQL用如下语句表示删除:
delete from r
where P;
其中P代表一个谓词,r 代表一个关系。delete 语句首先从r中找出所有使 P(t) 为真的元组t,然后把它们从r中删除。如果省略 where 子句,则 r 中所有元组将被删除。
注意 delete 命令只能作用于一个关系。如果我们想从多个关系中删除元组,必须在每个关系上使用一条 delete 命令。where 子句中的谓词可以和 select 命令的 where 子句中的谓词一样复杂。在另一种极端情况下 ,where 子句可以为空,请求
delete from instructor;
将删除 instructor 关系中的所有元组。instructor 关系本身仍然存在,但它变成空的了。