数据库原理(第七版)学习笔记二(第三章)

时间:2021-09-20 08:18:17

原创文章,欢迎转载,转载请注明出处(作者和链接)。


第三章 结构化查询语言

SQL命令分类:

  • 数据定义语言:DDL. 用于创建表、关系和其他结构。
  • 数据操作语言:DML. 查询、插入、修改和删除。
  • SQL/持久存储模块:SQL/PSM. 扩展了SQL,添加了过程式编程功能,例如变量和控制流语句。
  • 事务控制语言:TCL. 用于标记事务的边界,控制事务的行为。
  • 数据控制语言:DCL. 用于给用户和组赋予/取消数据库许可。

3.2、DDL创建表和关系

创建表结构基本格式:

CREATE TABLE NewTableName(
Columnname DataType OptionalConstraint,//列定义
Columnname DataType OptionalConstraint,
Columnname DataType OptionalConstraint,
optional table canstrains
...
);

列定义的三个部分分别为列名列数据类型列值的约束(可选)

列约束:PRIMARY KEY(主键)、FOREIGN KEY(候选键)、NOT NULL(不能为空)、NULL(允许为空)、UNIQUE(该列不能有重复值)、CHECK(介绍见后面)。

列数据类型(此处只列举SQL Server2014最常见的几种,详细可点击查看SQL数据类型):

常见数据类型
Bit 允许0、1或NULL
Int 4字节。允许从 -2,147,483,648 到 2,147,483,647 的所有数字。
Date 3字节。默认格式YYYY-MM-DD。
Char(n) n字节。固定长度的字符串。
Varchar(n) n字节。变长度的字符串,长度为0-8000字节。
Numeric(p,s)         带s位小数的p位数字,不存储小数点
BigInt 8字节的整型

举例:

CREATE TABLE EMPLOYEE(
EmployeeNumber Int PRIMARY KEY,
Name Char(25) NOT NULL,
Department Char(25) NOT NULL DEFAULT 'human resources',
Email VarChar(100) NOT NULL UNIQUE,
);

3.2.1 使用表约束定义主键

首先,必须为主键列提供列约束NOT NULL;然后使用CONSTRAINT标识的表约束来常见主键。例如:

CREATE TABLE EMPLOYEE(
EmployeeNumber Int NOT NULL,
Name Char(25) NOT NULL,
Department Char(25) NOT NULL DEFAULT 'human resources',
Email VarChar(100) NOT NULL UNIQUE,
CONSTRAINT EMPLOYEE_PK PRIMARY KEY(EmployeeNumber)
);

利用表约束常见逐渐的3个优点:

• 定义复合键的要求,因为PRIMARY KEY列约束不能用于多个列。当逐渐包含多个属性时,必须采用表约束方式定义主键。

• 使用表约束可以命名定义主键的约束。

• 可以方便的定义代理键。

定义代理键举例:

ProjectID    Int            NOT NULL IDENTITY(1000,100),
CONSTRAINT PROJECT_PK PRIMARY KEY(ProJectID)

IDENTITY关键字指示,在创建第一行时,这个代理键以值M开始,每添加一行,就递增N。所以ProjectID从1000开始,每添加一行递增100。


3.2.2 使用表约束定义外键

举例:

CREATE TABLE EMPLOYEE(
EmployeeNumber Int NOT NULL,
Name Char(25) NOT NULL,
Department Char(25) NOT NULL DEFAULT 'human resources',
Email VarChar(100) NOT NULL UNIQUE,
CONSTRAINT EMPLOYEE_PK PRIMARY KEY(EmployeeNumber),
CONSTRAINT EMP_DEPART_FK FOREIGN KEY(Department) REFERENCES DEPARTMENT(DepartmentName) 
ON UPDATE CASCADE
);

EMPLOYEE表的Department列是EMPLOYEE表的外键,它的取值必须在DEPARTMENT表的DepartmentName中存在对应项。

EMP_DEPART_FK定义了EMPLOYEE中的Department列和DEPARTMENT中的DepartmentName列之间的外键关系。

ON UPDATE CASCADE:ONUPDATE显示了在DEPARTMENT中的DepartmentName主键值改变时应执行的操作。关键字CASCADE表示应对EMPLOYEE表中的相同的Department列做相同的改变。

若为ONDELETE CASCADE:在删除DEPARTMENT表中的一行时,应级联删除EMPLOYEE表中的所有相关行。

若为ON DELETE/UPDATECASCADE:在删除/更新DEPARTMENT表中的一行时,不对EMPLOYEE做任何改变。

 

3.3 插入

两种情况:

1、提供了所有列的数据:

INSERT INTO DEPARTMENT VALUES(
'Administration', 3.1415, 123, '188-1068-8738'/*⚠️数字不需要用引号*/
);

2、缺少某些列的数据:

INSERT INTO PROJECT 
(ProName, Department, MaxHoues)
VALUES('2017-OFFER-COME', 'XUESAN', 12);

注意,列名的顺序必须与值的顺序一致。

3.4 SQL DML单表查询

 3.4.1 SELECT/FROM/WHERE架构

语法:

SELECT 列名1, 列名2, ...
FROM 表名
WHERE 指定条件

SELECT:指定在查询结果中要列出的

FROM:指定查询中使用的表

WHERE: 指定在查询结果中要列出的

如果希望去掉重复行,使用DISTINCT关键字:

SELECT DISTINCT 列名
FROM 表名

WHERE子句常使用的关键字:

1)结合多个条件:使用ANDOR关键字:

SELECT *
FROM PROJECT
WHERE Department = 'Finance'
AND Maxhours > 15;

2) IN/NOT IN:指定列值必须是/不是值集中的某一个

SELECT *
FROM PROJECT
WHERE Depetment IN('abs','ced','and');

3)BETWEEN:指定值的范围。包含两端的值。

SELECT *
FROM PROJECT
WHERE EmployName BETWEEN 'Amy' AND 'Mary';

4)(NOT)LIKE:

SELECT *
FROM PROJECT
WHERE EmployName LIKE 'Liu%';

% :百分号代表一个或多个未指定的字符

_ :下划线代表一个为指定的字符

5)IS (NOT) NULL:

SELECT *
FROM PROJECT
WHERE Phone IS NULL;


3.4.6 对查询结果进行排序

ORDER BY:默认情况下,SQL会按照升序排序。关键字ASC和DESC可指定升序或降序:

SELECT *
FROM PROJECT
ORDER BY Depertment DESC, LastName ASC;

把员工先按照Department降序排列,然后在Department中再按照LastName 升序排序。

3.4.7 SQL内置函数和计算

SQL的五个内置函数:

COUNT(列名):统计结果中行的数目。可作用于任何数据类型。

SUM(列名):统计一个数值列的总和。只能作用于数值型。

AVG(列名):平均值

MAX(列名):最大值

MIN(列名):最小值

FIRST(列名):第一条记录

LAST(列名):最后一条记录

例如:

SELECT COUNT(DISTINCT Department) AS NumOfDepartments
FROM PROJECT
WHERE ProjectId <= 120;

⚠️:除某些使用GROUP BY子句的情况外,列名不能和内置函数一起使用。

⚠️:内置函数不能用于WHERE子句。可用HAVING子句。

3.4.8 内置函数和分组

“Group By”从字面意义上理解就是根据“By”指定的规则对数据进行分组,所谓的分组就是将一个“数据集”划分成若干个“小区域”,然后针对若干个“小区域”进行数据处理。例如:

SELECT Department COUNT(*) AS NumOfEmployee
FROM EMPLOYEE
GROUP BY Department
HAVING COUNT(*) > 1

上述语句先将表根据Department划分成一个个小的区域,再分别对这些小区域求COUNT,然后筛选出COUNT(*)>1的部分。

⚠️:在select指定的字段要么就要包含在Group By语句的后面,作为分组的依据;要么就要被包含在聚合函数中。

⚠️:Having与Where的区别

where子句的作用时在对查询结果进行分组前,将不符合where条件的行去掉,即在分组之前过滤数据,where条件中不能包含聚合函数。使用where条件过滤特定的行。

having子句的作用时筛选满足条件的组,即在分组之后过滤数据,条件中经常包含聚合函数,使用having条件过滤出特定的组,也可以使用多个分组标准进行分组。

3.5 SQL DML——多表查询

3.5.1 使用子查询处理多个表

例如,要查找在某个任务中工作时间超过50个小时的所有雇员的姓名。雇员姓名存储在EMPLOYEE表中,但其工作时间存储在ASSIGNMENT表中:

SELECT FirstName, LastName
FROM EMPLOYEE
WHERE EmployeeNumber IN(
SELECT EmployeeNumber
FROM ASSIGNMENT
WHERE WorkHours > 50
);

3.5.2 使用 连接查询多个表

子查询只有在结果来自一个表时才有用,但如果要显示两个或多个表中的数据,子查询就无效。必须使用JOIN操作。

JOIN的基本思想是连接两个或多个表的内容,建立一个新表。例如:

SELECT FirstName, LastName, WorkHours
FROM EMPLOYEE AS E, ASSIGNMENT AS A
WHERE E.EmployeeNumber = A.EmployeeNumber;

该语句的作用是创建一个含有三列的新表。

3.5.3 SQL JOIN ON语法

上一个示例显示了旧式连接语法。新式连接语法JOIN ON:

SELECT FirstName, LastName, Workhours
FROM EMPLOYEE AS E JOIN ASSIGNMENT AS A
ON E.EmployeeNumber = A.EmployeeNumber

3.5.4 内连接和外连接

INNER JOIN:与JOIN相同。在表中存在至少一个匹配时返回行。

LEFT (OUTER) JOIN:从左表那里返回所有的行,即使在右表中没有匹配的行。

RIGHT (OUTER) JOIN:从右表那里返回所有的行,即使在左表中没有匹配的行。

FULL (OUTER) JOIN:会从左表和右表那里返回所有的行。如果左表 中的行在右表中没有匹配,或者如果右表中的行在左表中没有匹配,这些行同样会列出。

3.6 修改和删除关系的SQL语句

3.6.1 修改数据

语法:

UPDATE 表名
SET 属性1 = ‘新值’, 属性2 = '新值'
WHERE 选出要修改的行

3.6.2 删除数据

语法:

DELETE
FROM 表名
WHERE 选出要删除的行

删除表1的所有行:

DELETE 
FROM 表1

3.7 修改与删除表和约束的SQL语句

3.7.1 DROP TABLE

语法:

DROP TABLE 表名

删除表的结构以及所有数据。但如果该表的主键是其他表的外键,则删除无效。

3.7.2 ALTER TABLE

用于添加、修改、删除列和约束。

例如:删除外键约束:

ALTER TABLE ASSIGNMENT
DROP CONSTRAINT ASSIGN_EM_FK;

删除外键约束后就可以删除EMPLOYEE表了。

3.7.3 TRUNCATE TABLE语句

TRUNCATE TABLE EMPLOYEE;

同delete一样,删除表的数据,但不删除表结构。不能用where子句限定删除数据的条件。

3.7.4 CHECK约束

CHECK约束类似于WHERE子句,也可以包含IN、NOT IN、LIKE等进行范围检查。

例如:PROJECT表中,StartDate必须早于EndDate,但是表定义中没有任何语句实施这种约束。那么:

ALTER TABLE PROJECT
ADD CONSTRAINT Project_Check_Dates
CHECK(StartDate < EndDate);

再比如,要在PROJECT中添加一列:

ALTER TABLE PROJECT
ADD TotalHours Numeric(8,2) NULL;

将刚刚添加的列修改为NOT NULL:

ALTER TABLE PROJECT
ALTER COLUMN TotalHours Numeric(8,2) NOT NULL DEFAULT 1;

删除该列:

ALTER TABLE PROJECT
DROP COLUMN TotalHours;