本文最后更新于:2020年7月20日 晚上
一、SQL简介 1.1 SQL是什么
SQL是结构化查询语言,它是一种用于存储,操作和检索存储在关系数据库中的数据的计算机语言
关系型数据库可以通过E-R图转换而来,E-R图中矩形是实体集,菱形是关系,椭圆是属性。
1.2 SQL命令 1) DDL——数据定义语言
序号
命令
描述
1
CREATE
用于在数据库中创建新表,表视图或其他对象
2
ALTER
用于修改现有数据库对象,例如:表
3
DROP
用于删除整个表,数据库中的表或其他对象的视图
2) DML——数据操纵语言
序号
命令
描述
1
SELECT
从一个或多个表中检索某些记录
2
INSERT
创建一条记录
3
UPDATE
用于修改(更新)记录
4
DELETE
删除记录
3) DCL——数据控制语言
序号
命令
描述
1
GRANT
为用户提供权限
2
REVOKE
撤销用户授予的权限
1.3 数据的完整性 每个RDBMS(关系型数据库)都存在以下类别的数据完整性
实体完整性 - 表中没有重复的行。
域完整性 - 通过限制值的类型,格式或范围,为给定列强制执行有效条目。
参照完整性 - 其他记录使用(引用)导致这些行无法删除。
用户定义的完整性 - 实施一些不属于实体,域或参照完整性的特定业务规则
1.4 SQL约束
1.5 数据库范式 1) 第一范式(1NF)
在任何一个关系数据库中,第一范式(1NF)是对关系模式的基本要求,不满足第一范式(1NF)的数据库就不是关系数据库。
所谓第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。如果出现重复的属性,就可能需要定义一个新的实体,新的实体由重复的属性构成,新实体与原实体之间为一对多关系。在第一范式(1NF)中表的每一行只包含一个实例的信息。
简而言之,第一范式就是无重复的列。
2) 第二范式(2NF)
第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。第二范式(2NF)要求数据库表中的每个实例或行必须可以被唯一地区分。为实现区分通常需要为表加上一个列,以存储各个实例的唯一标识。这个唯一属性列被称为主关键字或主键、主码。
第二范式(2NF)要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性。如果存在,那么这个属性和主关键字的这一部分应该分离出来形成一个新的实体,新实体与原实体之间是一对多的关系。为实现区分通常需要为表加上一个列,以存储各个实例的唯一标识。
简而言之,第二范式就是非主属性部分依赖于主关键字 。
3) 第三范式(3NF)
满足第三范式(3NF)必须先满足第二范式(2NF)。简而言之,第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。
例如,存在一个部门信息表,其中每个部门有部门编号(dept_id)、部门名称、部门简介等信息。那么在员工信息表中列出部门编号后就不能再将部门名称、部门简介等与部门有关的信息再加入员工信息表中。如果不存在部门信息表,则根据第三范式(3NF)也应该构建它,否则就会有大量的数据冗余。
简而言之,第三范式就是属性不依赖于其它非主属性 。
1.6 运算符 假设变量a的值是:10,变量b的值是:20
1) SQL算术运算符
操作符
描述
示例
+
加法,执行加法运算。
a + b = 30
-
减法,执行减法运算。
a + b = -10
*
除法,执行除法运算
a * b = 200
/
用左操作数除右手操作数
b / a = 2
%
用左手操作数除左手操作数并返回余数
b % a = 0
1.7 在MySQL中创建表的示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 create database test default character set utf8 collate utf8_general_ci;CREATE TABLE regions ( region_id INT (11 ) AUTO_INCREMENT PRIMARY KEY, region_name VARCHAR (25 ) DEFAULT NULL );CREATE TABLE countries ( country_id CHAR (2 ) PRIMARY KEY, country_name VARCHAR (40 ) DEFAULT NULL , region_id INT (11 ) NOT NULL , FOREIGN KEY (region_id) REFERENCES regions (region_id) ON DELETE CASCADE ON UPDATE CASCADE );CREATE TABLE locations ( location_id INT (11 ) AUTO_INCREMENT PRIMARY KEY, street_address VARCHAR (40 ) DEFAULT NULL , postal_code VARCHAR (12 ) DEFAULT NULL , city VARCHAR (30 ) NOT NULL , state_province VARCHAR (25 ) DEFAULT NULL , country_id CHAR (2 ) NOT NULL , FOREIGN KEY (country_id) REFERENCES countries (country_id) ON DELETE CASCADE ON UPDATE CASCADE );CREATE TABLE jobs ( job_id INT (11 ) AUTO_INCREMENT PRIMARY KEY, job_title VARCHAR (35 ) NOT NULL , min_salary DECIMAL (8 , 2 ) DEFAULT NULL , max_salary DECIMAL (8 , 2 ) DEFAULT NULL );CREATE TABLE departments ( department_id INT (11 ) AUTO_INCREMENT PRIMARY KEY, department_name VARCHAR (30 ) NOT NULL , location_id INT (11 ) DEFAULT NULL , FOREIGN KEY (location_id) REFERENCES locations (location_id) ON DELETE CASCADE ON UPDATE CASCADE );CREATE TABLE employees ( employee_id INT (11 ) AUTO_INCREMENT PRIMARY KEY, first_name VARCHAR (20 ) DEFAULT NULL , last_name VARCHAR (25 ) NOT NULL , email VARCHAR (100 ) NOT NULL , phone_number VARCHAR (20 ) DEFAULT NULL , hire_date DATE NOT NULL , job_id INT (11 ) NOT NULL , salary DECIMAL (8 , 2 ) NOT NULL , manager_id INT (11 ) DEFAULT NULL , department_id INT (11 ) DEFAULT NULL , FOREIGN KEY (job_id) REFERENCES jobs (job_id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (department_id) REFERENCES departments (department_id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (manager_id) REFERENCES employees (employee_id) );CREATE TABLE dependents ( dependent_id INT (11 ) AUTO_INCREMENT PRIMARY KEY, first_name VARCHAR (50 ) NOT NULL , last_name VARCHAR (50 ) NOT NULL , relationship VARCHAR (25 ) NOT NULL , employee_id INT (11 ) NOT NULL , FOREIGN KEY (employee_id) REFERENCES employees (employee_id) ON DELETE CASCADE ON UPDATE CASCADE );
二、SQL数据库操作 语句SHOW DATABASES;
用于查看可用数据库列表。
2.0 帮助命令 help 如果不知道命令或者函数怎么用,可以使用help命令,mariaDB里面都会罗列出语法。
help help create table help join help trigger help grant
2.1 Create Database 语句 SQL中CREATE DATABASE
语句用于创建新的SQL数据库:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 CREATE {DATABASE| SCHEMA} [IF NOT EXISTS ] database_name [DEFAULT ] CHARACTER SET [= ]charset_name| [DEFAULT ] COLLATE [= ]collation_name;CREATE DATABASE testdb; mysql> show databases;+ | Database | + | information_schema | | mysql | | testdb | + 3 rows in set
数据库名称(database_name
)在RDBMS(关系数据库管理系统)
中必须是唯一的
2.2 Drop Database 语句 SQL中DROP DATABASE
语句用于删除SQL模式中已存在的数据库。
DROP DATABASE database_name;DROP DATABASE testdb; mysql> show databases;+ | Database | + | information_schema | | mysql | + 2 rows in set
2.3 Rename Database 语句 当需要更改数据库的名称时,将使用SQL RENAME DATABASE
RENAME DATABASE old_db_name TO new_db_name;ALTER DATABASE old_name MODIFY NAME = new_name;
2.4 Use 语句 如果SQL模式中有多个数据库,那么在开始操作之前,需要选择一个将执行操作的数据库。
SQL中的USE
语句用于选择SQL模式中的任何现有数据库。
USE database_name; mysql> SHOW DATABASES;+ | Database | + | information_schema | | mysql | | test | + 3 rows in set USE test;
三、表操作 3.1 创建表 Create Table CREATE [TEMPORARY] TABLE table_name( column_name_1 data_type default value column_constraint, column_name_2 data_type default value column_constraint, ..., table_constraint );
由table_name指定的表名在数据库中必须是唯一的
每个列定义由列名,列的数据类型 ,默认值和一个或多个列约束组成
列的数据类型指定列可以存储的数据类型。 列的数据类型可以是数字,字符,日期等
列约束控制可以存储在列中的值的类型。 例如,NOT NULL
约束确保列不包含NULL
值。列可能有多个列约束。 例如,users
表的username
列可以同时具有NOT NULL
和UNIQUE
约束 。
如果约束包含多个列,则使用表约束。 例如,如果表的主键包含两列,则在这种情况下,必须使用PRIMARY KEY
主键约束 。
TEMPORARY
关键字用于创建临时表,当断开与数据库连接时,mysql会自动删除它们。
CREATE TABLE courses ( course_id INT AUTO_INCREMENT PRIMARY KEY, course_name VARCHAR (50 ) NOT NULL );
CREATE TABLE trainings ( employee_id INT , course_id INT , taken_date DATE , PRIMARY KEY (employee_id , course_id) );
3.2 更新表 Alter Table 使用SQL ALTER TABLE
更改数据库中现有表的结构
ALTER TABLE
语句用于对现有表执行以下操作:
使用ADD
子句添加新列。
使用CHANGE
子句用于修改表中的列名称和数据类型。
使用ALTER SET DEFAULT
子句修改或删除表中指定列的默认值。
使用MODIFY
子句修改列的属性,例如:约束,默认值等。
使用DROP
子句删除列。
3.2.1 ALTER TABLE ADD列 该子句的作用是向表中添加一个或多个新列
ALTER TABLE table_nameADD [COLUMN ] column_name data_type column_constraint [AFTER existing_column];ALTER TABLE courses ADD credit_hours INT NOT NULL ;ALTER TABLE coursesADD COLUMN fee NUMERIC (10 , 2 ) AFTER course_name,ADD COLUMN max_limit INT AFTER course_name;
3.2.2 ALTER TABLE CHANGE列名称和属性 CHANGE
子句用于修改表中的列名称和数据类型。
ALTER TABLE table_name CHANGE [COLUMN ] column_name new_column_name column_properties;ALTER TABLE students CHANGE students_name names varchar (100 ) NOT NULL ;
3.2.3 ALTER TABLE ALTER SET DEFAULT列 ALTER [COLUMN] SET
子句修改或删除表中指定列的默认值。
ALTER TABLE table_nameALTER [COLUMN ] column_name SET DEFAULT 'xxx' ;ALTER TABLE customersALTER city SET DEFAULT 'beijing' ;
3.2.4 ALTERE TABLE MODIFY列 MODIFY子句用于更改现有列的数据类型。
ALTER TABLE table_name MODIFY [COLUMN ] column_name column_properties;ALTER TABLE students MODIFY name VARCHAR (20 ) NOT NULL ;
3.2.5 ALTER TABLE DROP列 当表的列已过时且未被任何其他数据库对象(如触发器,视图,存储过程和存储过程)使用时,将其从表中删除,请使用以下语法:
ALTER TABLE table_nameDROP [COLUMN ] column_name,DROP [COLUMN ] column_name, ...ALTER TABLE courses DROP fee;ALTER TABLE coursesDROP COLUMN max_limit,DROP COLUMN credit_hours;
3.2.6 ALTER TABLE RENAME TO RENAME TO
子句为表重新赋予一个表名。
ALTER TABLE table_name RENAME [TO ] new_table_name;ALTER TABLE classes RENAME new_classes;
3.3 删除表 DROP TABLE 使用SQL DROP TABLE
语句删除数据库中的一个或多个表
DROP [TEMPORARY] TABLE [IF EXISTS ] table_name [ RESTRICT | CASCADE ];DROP TABLE students;DROP TABLE IF EXISTS table_name1,table_name2,...;
DROP TABLE语句永久删除表的数据和结构,某些数据库系统要求表中的记录必须为空时才能从数据库中删除。这有助于防止意外删除仍在使用的表。
要删除表中的所有数据,可以使用DELETE 或TRUNCATE TABLE 语句。
要删除由另一个表的外键约束引用的表,必须在删除表之前禁用或删除外部约束。
3.4 快速删除表 TURNCATE TABLE 使用SQL TRUNCATE TABLE
语句高效,快速地删除表中的所有数据
TRUNCATE TABLE table_name; TRUNCATE TABLE IF EXISTS table_name1, table_name2, ...;TRUNCATE TABLE IF EXISTS students, teachers;
3.5 重命名表 RENAME TABLE SQL RENAME TABLE用于更改表的名称。
ALTER TABLE table_name RENAME [TO ] new_table_name; RENAME TABLE old_table_name To new_table_name;ALTER TABLE Students RENAME Student_bank; RENAME TABLE Student_bank TO Students;
3.6 复制表&临时表 1) 复制表 如果要将SQL表复制到同一数据库中的另一个表中,可以使用select
语句。
SELECT * INTO < destination_table> FROM < source_table> SELECT * INTO my_table_2 FROM my_table_1;
注意:SELECT INTO
与INSERT INTO
语句完全不同。
2) 临时表 临时表可以在运行时创建,并且可以像普通表一样执行各种操作,这些临时表是在tempdb
数据库中创建的。
根据行为和范围,有如下两种类型的临时表。1. 局部临时变量。 2. 全局临时变量。
① 局部临时变量
CREATE TABLE #local temp table ( User_id int , User_name varchar (50 ), User_address varchar (150 ) )
② 全局临时变量
CREATE TABLE ##new global temp table ( User_id int , User_name varchar (50 ), User_address varchar (150 )
3.7 查看表 3.7.1 查看表的名称 SHOW [FULL ] TABLES [{ FROM | IN } table_name] [ LIKE 'pattern' | WHERE expr];SHOW TABLES;
3.7.2 显示表的结构 SHOW [FULL ] COLUMNS {FROM | IN } table_name [{ FROM | IN } table_name] [ LIKE 'pattern' | WHERE expr]; {DESCRIBE | DESC } table_name [ col_name | wild ];DESC test.classes;
四、数据操作语句 4.1 INSERT语句 SQL提供了INSERT
语句,用于将一行或多行插入表中。 INSERT
语句用于:
向表中插入一行
向表中插入多行
将行从一个表复制到另一个表中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 INSERT [INTO ] table_name [(col_name,...)] {VALUES | VALUE } ({expr | DEFAULT },...),(...),...;INSERT [INTO ] table_name SET col_name= {expr | DEFAULT },...INSERT INTO table1 (column1, column2,...)SELECT column1, column2FROM table2WHERE condition1;INSERT students(class_id,name,gender,score)VALUE ('3' ,'小绿' ,'M' ,'95' );INSERT INTO temp(id,name)VALUES (2 ,'xiaoli' ), (3 ,'xiaowang' ), (4 ,'xiaojun' );INSERT INTO customers SET cust_name= '李四' ,cust_address= '武汉市' ,cust_sex= DEFAULT ;
4.2 Insert Into Select 在表中插入多行,可以将Insert
与select
语句结合使用。
INSERT INTO "table 1" ("column1", "column2",....) SELECT "column3", "column4",.... FROM "table2";
INSERT INTO
语句还可以包含许多子句,如:SELECT
,GROUP BY
,HAVING
以及JOIN
和ALIAS
。 因此,insert into select
语句可能会有些复杂。
INSERT INTO store (store_name, sales, transaction_date) SELECT store_name, sum (sales), transaction_date FROM sales_information GROUP BY store_name, transaction_date;
4.3 Update语句 使用SQL UPDATE
语句来修改表中现有行的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 UPDATE table_name SET col_name1= {expr1 | DEFAULT } [,col_name2 = {expr2 | DEFAULT }] ... [WHERE condition ] [ORDER BY ...] [LIMIT row_count]; UPDATE workersSET salary= 3000 WHERE salary< 3000 ; UPDATE dependentsSET last_name = ( SELECT last_name FROM employees WHERE employee_id = dependents.employee_id ); UPDATE instructorSET salary= case when salary<= 100000 then salary * 1.05 else salary * 1.03 end
4.4 UPDATE & JOIN语句 UPDATE JOIN
可使用一个表和连接条件来更新另一个表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 UPDATE customer_table INNER JOIN Customer_table ON customer_table.rel_cust_name = customer_table.cust_id SET customer_table.rel_cust_name = customer_table.cust_name UPDATE table1 t1LEFT JOIN table2 t2ON t1.column1 = t2.column1SET t1.column2 = t2.column2, t1.column3 = t2.column3where t1.column1 in (21 ,31 );
4.5 更新日期数据 要在SQL中更新日期和时间字段,则应使用以下查询。
UPDATE table SET Column_Name = 'YYYY-MM-DD HH:MM:SS' WHERE Id = value UPDATE table1SET EndDate = '2019-03-16 00:00:00.000' WHERE id in (1 ,3 );
4.6 DELETE语句 使用SQL DELETE
语句删除表中的一行或多行。
DELETE FROM table_nameWHERE condition ;DELETE FROM dependentsWHERE employee_id IN (100 , 101 , 102 );
五、SQL查询语句 SQL查询语句的通用形式:
select < [distinct ] c1,c2…> from < r1,……> [where < condition > ] [group by < c1,c2.…> [having < cond2> ]] [order by < c1[desc ] ,[c2[desc | asc ],…]>
SQL查询语句执行顺序:from→where→group(aggregate)→having→select→order by
5.1 SELECT语句 除了SELECT
和FROM
子句之外,SELECT
语句还可以包含许多其他子句,例如 -
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 SELECT [ALL | DISTINCT | DISTINCTROW ] select_expr [, select_expr ...] [FROM table_references [WHERE where_condition] [GROUP BY {col_name | expr | position} [ASC | DESC ], ... [WITH ROLLUP ]] [HAVING where_condition] [ORDER BY {col_name | expr | position} [ASC | DESC ], ...] [LIMIT {[offset ,] row_count | row_count OFFSET offset }]CASE WHEN 条件1 THEN 表达式1 WHEN 条件2 THEN 表达式2 ... WHEN 条件n THEN 表达式nELSE 表达式nEND SELECT employee_id, first_name, last_name, hire_dateFROM employees;SELECT employee_id, first_name, last_name, FLOOR (DATEDIFF(NOW(), hire_date) / 365 ) AS YoSFROM employees;SELECT name, CASE WHEN gender= 'M' THEN '男' ELSE '女' END AS 性别FROM students;
5.2 ORDER BY排序 SQL ORDER BY
子句根据指定的标准按升序或降序对结果集进行排序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 SELECT column1, column2FROM table_nameORDER BY column1 ASC , column2 DESC ; select class_id,count (* ) AS "人数" FROM students GROUP BY class_id HAVING count (* )>= 1 ORDER BY count (* );
5.3 DISTINCT运算符 使用SQL DISTINCT
运算符从结果集中删除重复数据项。
SELECT DISTINCT column1,column2......FROM table1;SELECT DISTINCT job_id, salaryFROM employeesORDER BY job_id, salary DESC ;
5.4 LIMIT子句 使用SQL LIMIT
子句来限制SELECT
语句返回的行数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 LIMIT {[offset ,] row_count | row_count OFFSET offset }SELECT employee_id, first_name, last_nameFROM employeesORDER BY first_name LIMIT 5 OFFSET 3 ;SELECT employee_id, first_name, last_name, salaryFROM employeesORDER BY salary DESC LIMIT 5 ;SELECT employee_id, first_name, last_name, salaryFROM employeesWHERE salary = (SELECT DISTINCT salary FROM employees ORDER BY salary DESC LIMIT 2 , 1 );
5.5 ALL,ANY,SOME语句 SQL ALL
与集合中所有元素比较;ANY
和SOME
与集合中的某些元素比较。
SELECT nameFROM instructorWHERE salary > SOME (SELECT salary FROM instructor WHERE dept_name= 'Biology' );SELECT dept_nameFROM instructorGROUP BY dept_namehaving avg (salary) >= ALL (SELECT avg (salary) FROM instructor GROUP BY dept_name);
5.6 BETWEEN | IN | LIKE | NULL 5.6.1 BETWEEN SQL BETWEEN
运算符选择指定范围内的值。
expression BETWEEN low AND high; expression NOT BETWEEN low AND high;SELECT employee_id, first_name, last_name, hire_dateFROM employeesWHERE hire_date BETWEEN '1999-01-01' AND '2000-12-31' ORDER BY hire_date;
5.6.2 IN SQL IN
运算符将列中的值与括号内的一组值进行比较。 要比较连续的值可用LIMIT
,比如5-100。
expression IN (value1,value2,...) expression NOT IN (value1, value2,...)SELECT employee_id, first_name, last_name, job_idFROM employeesWHERE job_id NOT IN (8 , 9 , 10 )ORDER BY job_id;
5.6.3 LIKE SQL LIKE
运算符来测试表达式是否与模式匹配。
要构造模式,请使用两个SQL通配符:
%
百分号匹配零个,一个或多个字符。
_
下划线符号匹配单个字符
下表说明了一些模式及其含义:
模式
含义
LIKE ‘Yii%’
匹配以Yii开始的字符串
LIKE ‘%su’
匹配以su结尾的字符串
LIKE ‘%ch%
匹配包含ch的字符串
LIKE ‘Luc_’
以Luc开始,后面只有一个字符,例如:Lucy,LucC等
LIKE ‘_cy’
以cy结尾,前面只有一个字符,例如:Lcy,ucy等
LIKE ‘%yiiBai_’
包含yiiBai,以任意数量的字符开头,最多以一个字符结尾。
LIKE ‘_yiiBai%’
包含yiiBai,最多以一个字符开头,以任意数量的字符结尾。
expression LIKE pattern expression LIKE pattern ESCAPE escape_characterSELECT employee_id, first_name, last_nameFROM employeesWHERE first_name LIKE 'M%' AND first_name NOT LIKE 'Ma%' ORDER BY first_name;
5.6.4 NULL 使用SQL IS NULL
和IS NOT NULL
运算符来测试表达式是否为NULL
。
NULL
表示数据未知的值,在数据库中缺少数据。
expression IS NULL ;SELECT employee_id, first_name, last_name, phone_numberFROM employeesWHERE phone_number IS NOT NULL ;
注意:
不能使用比较运算符的等于(=)将值与NULL
值进行比较
NULL
值是特殊的,任何与NULL
值的比较都不会返回true
或false
,而是返回未知
5.7 SQL别名 SQL别名,包括表和列别名,使查询更短,更易理解。
使用关键词AS
,可省略。
5.7.1 列别名 SELECT inv_no AS invoice_no, amount, due_date AS '截止日期' , cust_no '客户编号' FROM invoices;
5.7.2 表别名 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 SELECT d.department_nameFROM departments AS dSELECT employee_id, first_name, last_name, e.department_id, department_nameFROM employees eINNER JOIN departments d ON d.department_id = e.department_idORDER BY first_name;SELECT e.first_name AS employee, m.first_name AS managerFROM employees eLEFT JOIN employees m ON m.employee_id = e.manager_idORDER BY manager;
5.8 JOIN操作 SELECT
语句不仅能从单个表中查询数据,而且可以将多个表链接在一起。连接表的过程称为Join
。
SQL提供了多种连接,如内连接,左连接,右连接,全外连接等。
5.8.1 INNER JOIN SQL INNER JOIN
内连接子句来查询来自两个或多个表的数据。
内连接子句消除了与另一个表的行不匹配的行,相当于交集。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 SELECT A.nFROM AINNER JOIN B ON B.n = A.nSELECT first_name, last_name, employees.department_id, departments.department_id, department_nameFROM employees INNER JOIN departments ON departments.department_id = employees.department_idWHERE employees.department_id IN (1 , 2 , 3 );SELECT A.nFROM AINNER JOIN B ON B.n = A.nINNER JOIN C ON C.n = A.n;SELECT first_name, last_name, job_title, department_nameFROM employees eINNER JOIN departments d ON d.department_id = e.department_idINNER JOIN jobs j ON j.job_id = e.job_idWHERE e.department_id IN (1 , 2 , 3 );
5.8.2 LEFT JOIN 左连接将返回左表中的所有行,而不管右表中是否存在匹配的行,相当于AB交集后显示A。
SELECT A.nFROM ALEFT JOIN B ON B.n = A.n;SELECT c.country_name, c.country_id, l.country_id, l.street_address, l.cityFROM countries cLEFT JOIN locations l ON l.country_id = c.country_idWHERE c.country_id IN ('US' , 'UK' , 'CN' )
5.8.3 FULL OUTER JOIN 完全外连接是左连接和右连接的组合。完整外连接包括连接表中的所有行,相当于并集。
如果连接表中的行不匹配,则使用NULL值填充。
SELECT column_listFROM AFULL OUTER JOIN B ON B.n = A.n;SELECT basket_name, fruit_nameFROM fruitsFULL OUTER JOIN baskets ON baskets.basket_id = fruits.basket_idWHERE fruit_name IS NULL ;
5.8.4 Cross Join SQL Cross Join
交叉连接是一种连接操作,它生成两个或多个表的笛卡尔积。
SELECT column_listFROM table_ACROSS JOIN table_B;SELECT column_listFROM table_A,table_B;
5.8.5 自连接 SQL自连接技术将表连接到自身。
我们将一张表连接到自身来评估同一个表中其他行的行。 要执行自联接,我们使用内连接或左连接子句。
因为同一张表在单个查询中出现两次,所以必须使用表别名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 SELECT column1, column2, column3, ...FROM table1 AINNER JOIN table1 B ON B.column1 = A.column2;SELECT CONCAT(e.first_name, ' ' , e.last_name) as employee, CONCAT(m.first_name, ' ' , m.last_name) as managerFROM employees e INNER JOIN employees m ON m.employee_id = e.manager_idORDER BY manager;SELECT CONCAT(e.first_name, ' ' , e.last_name) as employee, CONCAT(m.first_name, ' ' , m.last_name) as managerFROM employees e LEFT JOIN employees m ON m.employee_id = e.manager_idORDER BY manager;
六、聚合函数 SQL聚合函数计算一组值并返回单个值。
因为聚合函数对一组值进行操作,所以它通常与SELECT
语句的GROUP BY
子句一起使用。GROUP BY
子句将结果集划分为值分组,聚合函数为每个分组返回单个值。
以下是常用的SQL聚合函数:
AVG() - 返回集合的平均值。
COUNT() - 返回集合中的项目数。
MAX() - 返回集合中的最大值。
MIN() - 返回集合中的最小值
SUM() - 返回集合中所有或不同值的总和。
6.1 AVG (平均) AVG()
函数返回集合中的平均值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 AVG ([ALL | DISTINCT ] expression)SELECT AVG (salary)FROM employees;SELECT ROUND(AVG (DISTINCT salary), 2 )FROM employees;SELECT department_id, AVG (salary)FROM employeesGROUP BY department_id;SELECT e.department_id, department_name, AVG (salary)FROM employees eINNER JOIN departments d ON d.department_id = e.department_idGROUP BY e.department_id;SELECT e.department_id, department_name, AVG (salary) AS avgsalaryFROM employees eINNER JOIN departments d ON d.department_id = e.department_idGROUP BY e.department_idHAVING avgsalary< 5000 ORDER BY AVG (salary) DESC ;SELECT AVG (employee_sal_avg)FROM ( SELECT AVG (salary) employee_sal_avg FROM employees GROUP BY department_id ) t;
6.2 COUNT(统计) SQL COUNT
函数来获取组中的项目数。它返回符合条件行数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 COUNT ([ALL | DISTINCT ] expression);SELECT e.department_id, department_name, COUNT (* )FROM employees eINNER JOIN departments d ON d.department_id = e.department_idGROUP BY e.department_id;SELECT e.department_id, department_name, COUNT (* )FROM employees eINNER JOIN departments d ON d.department_id = e.department_idGROUP BY e.department_idHAVING COUNT (* ) > 5 ORDER BY COUNT (* ) DESC ;
6.3 SUM(求和) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 SUM ([ALL | DISTINCT ] expression)SELECT e.department_id, department_name, SUM (salary)FROM employees eINNER JOIN departments d ON d.department_id = e.department_idGROUP BY e.department_idHAVING SUM (salary) > 30000 ORDER BY SUM (salary) DESC ;
6.4 MAX & MIN SQL Max
函数查找组中的最大值,Min
函数查找组中的最小值。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 MAX (expression)MIN (expression)SELECT employee_id, first_name, last_name, salaryFROM employeesWHERE salary = ( SELECT MAX (salary) FROM employees );SELECT d.department_id, department_name, MAX (salary)FROM employees eINNER JOIN departments d ON d.department_id = e.department_idGROUP BY e.department_idORDER BY MAX (salary) DESC ;SELECT d.department_id, department_name, MAX (salary)FROM employees eINNER JOIN departments d ON d.department_id = e.department_idGROUP BY e.department_idHAVING MAX (salary) > 12000 ;
6.6 Group By子句 GROUP BY
子句是SELECT
语句的可选子句,它根据指定列中的匹配值将行组合成组,每组返回一行。
[GROUP BY {col_name | expr | position} [ASC | DESC ], ... [WITH ROLLUP ]]SELECT cust_address,cust_sex,COUNT (* ) AS "人数" FROM customers GROUP BY cust_address,cust_sex WITH ROLLUP ;
6.6 HAVING SQL HAVING
子句,该子句用于为GROUP BY
子句汇总的组指定条件,一般搭配GROUP BY
子句使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 SELECT column1, column2, AGGREGATE_FUNCTION (column3)FROM table1GROUP BY column1, column2HAVING group_condition;SELECT class_id,count (* ) AS "人数" FROM students GROUP BY class_id HAVING count (* )> 1 ;
七、高级查询 7.1 GROUPING SETS运算符 使用SQL GROUPING SETS
运算符生成多个分组集
分组集是一组使用GROUP BY
子句进行分组的列。 通常,单个聚合查询定义单个分组集
SELECT c1, c2, aggregate (c3)FROM table GROUP BY GROUPING SETS ( (c1, c2), (c1), (c2), () );
7.2 ROLLUP运算符 ROLLUP
是GROUP BY
子句的扩展。ROLLUP
选项允许包含表示小计的额外行,通常称为超级聚合行,以及总计行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 SELECT c1, c2, aggregate_function(c3)FROM table GROUP BY ROLLUP (c1, c2);SELECT COALESCE (warehouse, 'All warehouses' ) AS warehouse, SUM (quantity)FROM inventoryGROUP BY ROLLUP (warehouse);SELECT warehouse, product, SUM (quantity)FROM inventoryGROUP BY warehouse, ROLLUP (product);
7.3 UNION运算符 (并集) 使用SQL UNION
组合来自多个查询的两个或多个结果集,UNION
运算符将两个或多个SELECT
语句的结果集合并到一个结果集中,相当于并集。
SELECT column1, column2FROM table1UNION [ALL ]SELECT column3, column4FROM table2;
7.4 INTERSECT(交) SQL INTERSECT
运算符,来获取两个或多个查询的交集。
SELECT idFROM aINTERSECT SELECT idFROM b;
要使用INTERSECT
运算符,SELECT
语句的列需要遵循以下规则:
列的数据类型必须兼容。
SELECT
语句中的列数及其顺序必须相同
7.5 MINUS(差) SQL MINUS
运算符从另一个结果集中减去一个结果集。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 SELECT idFROM A MINUSSELECT idFROM B;SELECT employee_idFROM employees MINUSSELECT employee_idFROM dependentsORDER BY employee_id;
7.6 子查询 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 SELECT employee_id, first_name, last_nameFROM employeesWHERE department_id NOT IN (SELECT department_id FROM departments WHERE location_id = 1700 )ORDER BY first_name , last_name;SELECT employee_id, first_name, last_name, salaryFROM employeesWHERE salary > (SELECT AVG (salary) FROM employees);
7.7 EXISTS运算符 EXISTS
运算符用于指定子查询以测试行的存在。如果子查询包含任何行,则返回true
。否则,它返回false
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 EXISTS (subquery)NOT EXISTS (subquery)SELECT department_nameFROM departments dWHERE NOT EXISTS ( SELECT 1 FROM employees e WHERE salary > 10000 AND e.department_id = d.department_id)ORDER BY department_name;
八、约束 完整性约束保证授权用户对数据库所做的修改不会破坏数据的一致性。
8.1 实体完整性-主键约束
每个表都有一个且只有一个主键。 主键不接受NULL
或重复值。
如果主键由两列或更多列组成,则值可能在一列中重复,但主键中所有列的值组合必须是唯一的。
复合主键不能包含不必要的多余列。
CREATE TABLE project_assignments ( project_id INT , employee_id INT , join_date DATETIME NOT NULL , CONSTRAINT pk_assgn PRIMARY KEY (project_id , employee_id) );ALTER TABLE project_milestonesADD PRIMARY KEY (milestone_id);ALTER TABLE project_milestonesDROP CONSTRAINT pk_milestone_id;
8.2 实体完整性-唯一约束 使用SQL UNIQUE
约束强制列或一组列中值的唯一性
UNIQUE
约束定义了一个规则,该规则可防止存储在不参与主键的特定列中有重复值
UNIQUE
约束和PRIMARY KEY
约束之间的区别: 比较项|PRIMARY KEY
约束|UNIQUE
约束 -|-|- 约束的数量|一个|多个 NULL值|不允许|允许
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 CREATE TABLE users ( user_id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR (255 ) NOT NULL UNIQUE , password VARCHAR (255 ) NOT NULL );CREATE TABLE users ( user_id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR (255 ) NOT NULL , password VARCHAR (255 ) NOT NULL , CONSTRAINT uc_username UNIQUE (username) );ALTER TABLE usersADD CONSTRAINT uc_username UNIQUE (username);ALTER TABLE usersADD new_column data_type UNIQUE ;ALTER TABLE table_nameDROP CONSTRAINT unique_constraint_name;
8.3 参照完整性-外键约束 SQL外键FOREIGN KEY
约束以强制表之间的关系。
定义外码的主要目的是:让系统做参照完整性约束的检查。
参照关系中外码的值必须在被参照关系中实际存在或为null 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name, ...) REFERENCES tbl_name (index_col_name,...) [ON DELETE reference_option] [ON UPDATE reference_option] RESTRICT | CASCADE | SET NULL | NO ACTION
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 CREATE TABLE project_milestones ( milestone_id INT AUTO_INCREMENT PRIMARY KEY, project_id INT , milestone_name VARCHAR (100 ), FOREIGN KEY (project_id) REFERENCES projects (project_id) );CREATE TABLE project_milestones ( milestone_id INT AUTO_INCREMENT PRIMARY KEY, project_id INT , milestone_name VARCHAR (100 ), CONSTRAINT fk_project FOREIGN KEY (project_id) REFERENCES projects (project_id) );CREATE TABLE orders ( order_id INT NOT NULL AUTO_INCREMENT, order_product CHAR (50 ) NOT NULL , order_product_type CHAR (50 ) NOT NULL , cust_id INT NOT NULL , order_date DATETIME NOT NULL , order_price DOUBLE NOT NULL , order_amount INT NOT NULL , PRIMARY KEY(order_id), FOREIGN KEY(cust_id) REFERENCES customers(cust_id) ON DELETE RESTRICT ON UPDATE RESTRICT );ALTER TABLE table_1ADD CONSTRAINT fk_name FOREIGN KEY (fk_key_column) REFERENCES table_2(pk_key_column)ALTER TABLE table_nameDROP CONSTRAINT fk_name;
8.4 用户定义完整性-NOT NULL NOT NULL
约束是一个列约束,它定义将列限制为仅具有非NULL
值的规则。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 CREATE TABLE table_name( ... column_name data_type NOT NULL , ... );CREATE TABLE training ( employee_id INT , course_id INT , taken_date DATE NOT NULL , PRIMARY KEY (employee_id , course_id) );ALTER TABLE training MODIFY taken_date date NOT NULL ;
8.5 用户定义完整性-CHECK约束 CHECK
约束是SQL中的完整性约束,它允许指定列或列集中的值必须满足布尔表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 CHECK (Boolean_expression)CONSTRAINT constraint_name CHECK (Boolean_expression)CREATE TABLE products ( product_id INT PRIMARY KEY, product_name VARCHAR (255 ) NOT NULL , selling_price NUMERIC (10 ,2 ) CHECK (selling_price > 0 ) );CREATE TABLE products ( product_id INT PRIMARY KEY, product_name VARCHAR (255 ) NOT NULL , selling_price NUMERIC (10 ,2 ) CONSTRAINT positive_selling_price CHECK (selling_price > 0 ) );CREATE TABLE products ( product_id INT PRIMARY KEY, product_name VARCHAR (255 ) NOT NULL , selling_price NUMERIC (10 , 2 ) CHECK (selling_price > 0 ), cost NUMERIC (10 , 2 ) CHECK (cost > 0 ), CONSTRAINT valid_selling_price CHECK (selling_price > cost) );
8.6 域约束 create domain
域约束是完整性约束的最基本形式,可用于检测插入到数据库中的数据的合法性
create domain Dollars as numeric (12 ,2 ) not null create domain Pounds as numeric (12 ,2 );create table instructor (ID char (5 ) primary key, name varchar (20 ), dept name varchar (20 ), salary Dollars, comm Pounds );
九、视图与索引 9.1 视图 在某些情况下,让所有用户看到整个逻辑模型是不合适的,视图就提供了这种机制:向用户隐藏特定的数据。
SQL允许通过查询来定义“虚关系”,它在概念上包含查询的结果,但并不预先计算并存储。像这种作为虚关系对用户可见的关系称为视图(view)。
9.1.1 创建视图 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 CREATE [OR REPLACE] VIEW view_name [(column_list)] AS select_statement [WITH [CASCADED | LOCAL ] CHECK OPTION]create view physics_fall_2009_watson as select course_id, room_numberfrom physics_fall_2009where building= 'Watson' ;CREATE OR REPLACE VIEW mysql_test.customers_view AS SELECT * FROM mysql_test.customers WHERE cust_sex= 'M' WITH CHECK OPTION;
9.1.2 删除视图 DROP VIEW [IF EXISTS ] view_name [, view_name] ... [RESTRICT | CASCADE]
9.1.3 更新视图 ALTER VIEW view_name [(column_list)] AS select_statement [WITH [CASCADED | LOCAL ] CHECK OPTION]
9.1.4 查看视图定义 SHOW CREATE VIEW view_name
9.1.5 更新视图数据 一般地,如果定义视图的查询能满足下列条件,我们称SQL视图是可更新的(updatable),即视图上可以执行插入、更新或删除
from
子句中只有一个数据库关系
select
子句中只包含关系的属性名,不包含任何表达式、聚集或distinct
声明
任何没有出现在select
子句中的属性可以取空值;即这些属性上没有not null
约束,也不构成主码的一部分
查询中不含有group by
或having
子句
insert into faculty values (‘30765 ',‘Green' ,‘Music'); /*该语句能够成功执行,是因为创建视图时添加了WITH CHECK OPTION*/ /*示例2--使用UPDATE语句通过视图修改基本表的数据*/ UPDATE mysql_test.customers_view SET cust_address=' 上海市'; /*示例3--使用DELETE语句通过视图删除基本表的数据*/ DELETE FROM mysql_test.customers_view WHERE cust_name=' 周明';
9.2 索引 9.2.1 索引的创建 我们用create index
命令,为关系中的某些属性创建索引。索引,就是DBMS根据表中的一列或若干列按照一定顺序建立的列值与记录行之间的对应关系表,因而索引实质上是一张描述索引列的列值与原表中的记录行之间一对应关系的有序表。
更新表的时候索引会被自动更新,因此索引提高查询速度,降低更新速度。
9.2.1.1 使用CREATE INDEX语句 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 CREATE [ONLINE| OFFLINE] [UNIQUE | FULLTEXT| SPATIAL] INDEX index_name [index_type] ON tbl_name (index_col_name,...) [index_option] ...CREATE [UNIQUE ] INDEX index_name ON table_name (index_col_name,...);CREATE INDEX index_students ON students(name(3 ) ASC );CREATE UNIQUE INDEX uni_stu_index ON student(ID,name);
9.2.1.2 使用CREATE TABLE语句 {INDEX | KEY} [index_name] (index_col_name,...)CREATE TABLE seller ( seller_id INT NOT NULL AUTO_INCREMENT, seller_name char (50 ) NOT NULL , product_type int (5 ) NULL , sales INT NULL , PRIMARY KEY(seller_id,product_type), KEY index_seller(sales) );
9.2.1.3 使用ALTER TABLE语句 ADD {INDEX | KEY} [index_name] (index_col_name,...)ALTER TABLE seller ADD INDEX index_seller_name (seller_name);
9.2.2 索引的查看 SHOW {INDEX | INDEXES | KEYS} {FROM | IN } tbl_name [{FROM | IN } db_name] [WHERE expr]SHOW KEYS IN seller;
9.2.3 索引的删除 9.2.3.1 使用DROP INDEX语句 DROP [ONLINE| OFFLINE] INDEX index_name ON tbl_nameDROP INDEX index_seller_name ON seller;
9.2.3.2 使用ALTER TABLE语句 在ALTER TABLE语句下面添加以下一项。
DROP PRIMARY KEY;DROP INDEX index_name;ALTER TABLE seller DROP PRIMARY KEY, DROP INDEX index_seller;
十、断言及触发器 10.1 断言 断言(assertion)是表达要求数据库永远满足的条件的谓词(复杂check条件)
SQL中的断言形式如下:
create assertion < assertion_name> check < predicate>
创建了某断言之后,系统将检查它的合法性,并对每一个可能破坏该断言的数据库更新进行检测这种检测会产生大量的开销,因此断言的使用应非常谨慎
create assertion ins_teaches_constraint check not exists (select ID,name,section_id,semester,year ,time_slot_id, count (distinct building,room,number)from instructor natural join teaches natural join sectiongroup by (ID,name,section_id,semester,year ,time_slot_id)having count (building,room_number)> 1 )
10.2 触发器trigger 触发器(trigger)是由数据库更新操作引起的被系统自动执行的语句。
设计触发器必须:
指明触发器被执行的条件
指明触发器执行时所做的具体操作
1) 创建触发器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 CREATE TRIGGER trigger_name trigger_time trigger_event ON tbl_name FOR EACH ROW trigger_bodyCREATE TRIGGER mysql_test.customers_insert_trigger AFTER INSERT ON mysql_test.customers FOR EACH ROW SET @str = NEW.cust_id;CREATE TRIGGER mysql_test.customers_update_trigger BEFORE UPDATE ON mysql_test.customers FOR EACH ROW SET NEW.cust_address= OLD.cust_contact;create trigger timeslot_check1 after insert ON section referencing new row as nrow for each row when (nrow.time_slot_id not in (select time_slot_id from time_slot))begin rollback end ;create trigger reorder_trigger after update of level on inventory referencing old row as orow, new row as nrow for each row when nrow.level<= (select level from minlevel where minlevel.item= nrow.item) and orow.level> (select level from minlevel where minlevel.item= orow.item)begin insert into ordersbegin insert into orders (select item, amount from reorder where reorder.item= orow.item)end
2) 删除触发器
DROP TRIGGER [IF EXISTS ] [schema_name.]trigger_nameDROP TRIGGER IF EXISTS mysql_test.customers_insert_trigger;
十一、 安全性 11.1 用户账号管理 11.1.1 创建账户 CREATE USER user [IDENTIFIED BY [PASSWORD] 'password' ]SELECT PASSWORD(456 );>> * 531E182 E2F72080AB0740FE2F2D689DBE0146E04CREATE USER 'zhangsan' @'localhost' IDENTIFIED BY '123' , 'lisi' @'localhost' IDENTIFIED BY PASSWORD '*531E182E2F72080AB0740FE2F2D689DBE0146E04' ;
11.1.2 删除账户 DROP USER [IF EXISTS ] user [, user ] ...DROP USER lisi@localhost ;
11.1.3 修改用户账号 RENAME USER old_user TO new_user [, old_user TO new_user] ... RENAME USER 'zhangsan' @'localhost' TO 'wangwu' @'127.0.0.1' ;
11.1.4 修改用户口令 SET PASSWORD [FOR user ] = { PASSWORD('cleartext password' ) | 'encrypted password' }SET PASSWORD FOR 'bob' @'%.example.org' = PASSWORD('cleartext password' );
11.2 用户权限管理 新创建的账户没有访问权限,不能执行任何数据库操作。
SHOW GRANTS FOR 'user_name' @'host_name' ;
11.2.1 权限的授予 GRANT priv_type [(column_list)] [, priv_type [(column_list)]] ... ON [object_type] priv_level TO user_specification [, user_specification] ... [WITH with_option ...]
其中priv_type
可有以下选择:
select
、insert
、update
、delete
:允许读关系,或查询视图、插入元组、修改元组、删除元组
references
:创建关系时允许声明外键
CREATE
、ALTER
、DROP
: 允许创建表、修改表、删除表权限
INDEX
:允许定义索引权限
CREATE ROUTINE
、ALTER ROUTINE
、EXECUTE ROUTINE
:允许创建、更新/删除、调用特定数据库的存储过程和存储函数的权限
CREATE USER
、SHOW DATABASES
:允许创建或删除新用户、查看已有数据库的定义的权限
all privileges
:所有权限
with grant option
:允许用户把被授予的权限再转授给其他用户
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 GRANT SELECT (cust_id,cust_name) ON mysql_test.customers TO 'zhangsan' @'localhost' ;GRANT SELECT ,UPDATE ON mysql_test.customers TO 'liming' @'127.0.0.1' IDENTIFIED BY '123' 'huang' @'127.0.0.1' IDENTIFIED BY '789' ;GRANT ALL ON mysql_test.* TO 'wangwu' @'localhost' ;GRANT CREATE USER ON * .* TO 'wangwu' @'localhost' ;GRANT ALL PRIVILEGES ON * .* TO 'root' @'%' IDENTIFIED BY '登录密码' ; flush privileges;
11.2.2 权限的转移 with grant option
使用这条语句,可把自身拥有的权限赋予其他人
11.2.3 权限的撤销 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 REVOKE priv_type [(column_list)] [, priv_type [(column_list)]] ... ON [object_type] priv_level FROM user [, user ] ...REVOKE ALL PRIVILEGES, GRANT OPTION FROM user [,user ] ...revoke select on mysql_test.customers from 'tom' @'localhost' ;revoke select on instructor from U1,U2,U3 restrict;
11.3 审计跟踪 分为语句审计和对象审计
AUDIT < st- opt> [BY < users> ] [BY SESSION | ACCESS] [WHENEVER SUCCESSFUL | WHENEVER NOT SUCCESSFUL] audit table by scott by access whenever successful;
AUDIT < obj- opt> ON < obj> | DEFAULT [BY SESSION | BY ACCESS] [WHENEVER SUCCESSFUL | WHENEVER NOT SUCCESSFUL] audit delete ,update on student;
11.4 事务 11.4.1 事务的概念 当多个用户同时更新时,为了保证数据库的正确性,避免数据库的不一致性,控制这种并发操作的机制称为“并发控制”。而事务就是为保证数据的一致性而产生的一个概念和基本手段。
事务(transaction)用户定义的一个数据操作序列,是一个完整的工作单元,要么全部执行,要么全部不执行。
事务以BEGIN TRANSACTION
语句开始。
下列SQL语句之一会结束一个事务:
Commit
:提交当前事务,也就是将该事务所做的更新在数据库中持久保存。在事务被提交后,一个新的事务自动开始
Rollback
:回滚当前事务,即撤销该事务中所有SQL语句对数据库的更新。这样,数据库就恢复到执行该事务第一条语句之前的状态
11.4.2 事务的特征 为保证数据一致性和正确性,数据库确保事务具有如下4个特征,简称事务的ACID特征:
原子性(Atomicity):一组更新操作是原子不可分。
一致性(Consistency):满足数据库完整性约束。
隔离性(Isolation):事务彼此独立,隔离,不被其他事务干扰。一个执行完,另一个才能存取。
持续性(Durability):一旦提交,对数据的改变是永久的。
11.4.3 并发操作问题 事务的ACID特征可能遭到破坏的原因之一是多个事务对数据库的并发操作造成的。
典型的并发操作问题有如下三个:
丢失更新:读入同一数据并修改,导致之前修改丢失。
不可重复读:读第一次和读第二次的结果不一样,因为别人在中间修改插入删除了某些数据
事务T1读取某一数据后,T2对其修改,T1再次读到与之前不一样的值。
T1读取某一数据后,T2删除部分记录,T1再次读发现某些记录丢失了。
T1读取某一数据后,T2插入一些记录,T1再次读发现多了一些记录。
读‘脏’数据:T1修改某一数据并写回,T2读取,T1撤销操作,T2的数据便是脏数据
11.4.4 封锁 封锁是最常用的并发控制技术。原理是:需要时,事务通过向系统请求对它所希望的数据对象加锁,确保它不被非预期改变。
11.4.4.1 封锁类型 基本的封锁类型有两种:排他锁(X锁)、共享锁(S锁)。
排他锁:写锁 。若事务T对数据对象A加上X锁,则只允许T读取和修改A,其他任何事务都不能再对A加任何类型的锁,直到T释放A上的锁为止。这就保证了其他事务在T释放A上的锁之前不能再读取和修改A。
共享锁:读锁 ,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁为止,这就保证了其他事务可以读A,但在T上释放A的S锁之前不能对A做任何修改。
11.4.4.2 封锁协议
一级封锁协议:事务T在修改数据R前必须先对其加X锁,直到事务结束才释放。只能保证不发生丢失修改。
二级封锁协议:在一级封锁协议基础上,增加事务T在读取数据R前必须先对其加S锁,读完后即可释放S锁。增加保证了不发生读“脏”数据
三级封锁协议:在一级封锁协议的基础上,增加事务T在读取数据R前必须先对其加S锁,直到事务结束才释放进一步防止了不可重复读
封锁协议级别越高,一致性程度越高
11.4.4.3 活锁与死锁
避免活锁最简单的方法是“先来先服务”。
两个以上事务循环等待被同组中另一事务锁住的数据单元的情形,称为“死锁”。
预防死锁的办法:
一次封锁法:每个事务必须一次将所有要使用的数据全部加锁。 缺点:降低了系统的并发度。而且数据是不断变化的,很难事先精确确定每个事务所要封锁的数据对象。
顺序封锁法:预先对数据对象规定一个封锁顺序,所有事务都按这个顺序实现封锁。 缺点:封锁的数据对象极多且在不断变化。事务的封锁请求随着事务的执行而动态地决定,很难事先确定。
序列化处理:通过应用设计为每一数据单元建立“主人程序”,所有请求发给“主人”,而“主人”以单道运行。 缺点:系统性能、数据完整性可能受到影响。
资源剥夺:每当事务因锁请求不能满足而受阻,强行令冲突中的一方回滚,释放所有锁,然后重新运行。 缺点:需要预防活锁发生。
死锁的诊断与解除
超时法:实现简单,用得最多 缺点:可能误判。若时限太长不能及时发现
等待图法:精确判断死锁
11.4.4.4 可串行性 定义:若一个调度等价于某一串行高度,即它所产生的结果与某一串行调度的结果一样,称这种调度是可串行化的。
两段封锁法是一种简单有效的保障封锁其调度是可串行性的方法。
两段封锁法:所有事务必须分两个阶段对数据项进行加锁和解锁
在对任何数据进行读写操作之前,首先要申请并获得对该数据的封锁
在释放一个封锁之后,事务不再申请和获得任何其他封锁
事务分为两个阶段:
获得封锁,也称为扩展阶段,可以申请获得任何数据项上的任何类型的锁,不能释放任何锁
释放封锁,也称为收缩阶段,可以释放任何锁,但是不能申请任何锁
可以证明,若并发执行的所有事务均遵守两段锁协议,则对这些事务的任何并发调度策略都是可串行化的(充分不必要条件),但是可能导致死锁。
11.5 备份与恢复表
用SELECT INTO … OUTFILE备份数据
用LOAD DATA…INFILE恢复数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 SELECT * INTO OUTFILE 'file_name' export_options | INTO DUMPFILE 'file_name' [{FIELDS | COLUMNS} [TERMINATED BY 'string' ] [[OPTIONALLY] ENCLOSED BY 'char' ] [ESCAPED BY 'char' ] ] [LINES TERMINATED BY 'string' ] LOAD DATA INFILE 'file_name' INTO TABLE tbl_name [{FIELDS | COLUMNS} [TERMINATED BY 'string' ] [[OPTIONALLY] ENCLOSED BY 'char' ] [ESCAPED BY 'char' ] ] [LINES [STARTING BY 'string' ] [TERMINATED BY 'string' ] ]SELECT * FROM mysql_test.customers INTO OUTFILE 'C:/BACKUP/backupfile.txt' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY "" LINES TERMINATED BY '?' ; LOAD DATA INFILE 'C:/BACKUP/backupfile.txt' INTO TABLE mysql_test.customers_copy FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY "" LINES TERMINATED BY '?' ;
注意:多个用户使用MYSQL时,备份时在指定表上使用LOCK TABLES table_name READ
语句做个读锁定,防止备份中被其他用户更新;恢复时使用LOCK TABLES table_name WRITE
语句做个写锁定,防止数据冲突。备份恢复完成后,用UNLOCK TABLES
语句对该表进行解锁。
十二、 数据库编程 12.1 存储过程 12.1.1 存储过程的基本概念 存储过程是一组SQL语句编译成一个SQL。类似于批量处理的SQL脚本。
存储过程的好处:
可增强SQL语言的功能和灵活性
良好的封装性
高性能
可减少网络流量
存储过程可作为一种安全机制来确保数据库的安全性和数据的完整性
12.1.2 创建存储过程 delimiter
是MySQL
中的命令,这个命令与存储过程没什么关系。
其实就是告诉mysql
解释器,该段命令是否已经结束了,mysql是否可以执行了。即改变输入结束符。
默认情况下,delimiter
是分号“;”。
但有时候,不希望MySQL
这么做。因为可能输入较多的语句,且语句中包含有分号。
默认情况下,mysql
一遇到分号,它就要自动执行。
这种情况下,就可以使用delimiter
,把delimiter
后面换成其它符号,如//
或$$
。
此时,delimiter
作用就是对整个小段语句做一个简单的封装。
每次使用完要记得换回原来的分号;
使用CREATE PROCEDURE
来创建存储过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 CREATE PROCEDURE sp_name ([proc_parameter[,...]]) routine_body use test; delimiter $$CREATE PROCEDURE sp_update_sex (IN cid INT ,IN csex CHAR (1 ))BEGIN UPDATE customers SET cust_sex= csex WHERE cust_id= cid;END $$ delimiter ;
12.1.3 存储过程体 12.1.3.1 局部变量 使用DECLARE
语句来声明局部变量。
DECLARE var_name [, var_name] ... type [DEFAULT value ]DECLARE cid INT (10 );
12.1.3.2 SET语句 SET
为局部变量赋值。
SET var_name= expr [, var_name= expr] ...SET cid= 910 ;
12.1.3.3 SELECT…INTO语句 SELECT...INTO
语句把选定列的值直接存储到局部变量中。
SELECT col_name [,...] INTO var_name [,...] table_expr
12.1.3.4 游标 在使用SELECT
语句检索时,返回的是一个结果集数据行,该结果集中有多行数据,这些数据无法被一行行的进行处理,此时,需要使用游标。
游标是一个被SELECT
语句检索出来的结果集。在存储了游标后,应用程序或用户就可以根据需要滚动或浏览其中的数据。使用游标的步骤如下:
1) 声明游标
DECLARE cursor_name CURSOR FOR select_statement
2) 打开游标
必须打开游标才能使用。
3) 读取数据
FETCH cursor_name INTO var_name [,var_name] ...
4) 关闭游标
5) 示例
创建一个存储过程,用于计算表customers中数据行的行数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 delimiter $$create procedure sp_sumofrow(out rows int )begin declare cid int ; declare found boolean default true ; declare cur_cid cursor for select cust_id from customers; declare continue handler for not found set found= false ; set rows = 0 ; open cur_cid; fetch cur_cid into cid; while found do set rows = rows + 1 ; fetch cur_cid into cid; end while; close cur_cid;end $$ delimiter ;
12.1.4 调用存储过程 CALL sp_name([parameter [,...]]);CALL sp_name[()];CALL sp_update_sex(909 ,'M' );
12.1.5 删除存储过程 DROP PROCEDURE [IF EXISTS ] sp_name;DROP PROCEDURE IF EXISTS sp_update_sex;
12.2 存储函数 存储过程和存储函数的区别:
存储函数不能拥有输出参数,自身即是输出参数;存储过程可以拥有输出参数
存储函数可以被直接调用,而存储过程必须通过CALL语句调用
存储函数中必须包含一条RETURN语句,而这条特殊的SQL语句不允许包含于存储过程中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 CREATE FUNCTION sp_name ([func_parameter[,...]]) RETURNS type routine_body USE test; DELIMITER $$CREATE FUNCTION fn_search(cid INT ) RETURNS CHAR (2 )BEGIN DECLARE SEX CHAR (2 ); SELECT gender INTO SEX FROM students WHERE id= cid; IF SEX IS NULL THEN RETURN (SELECT "没有该学生"); ELSE IF SEX= 'F' THEN RETURN (SELECT '女' ); ELSE RETURN (SELECT '男' ); END IF; END IF;END $$ DELIMITER ;SELECT sp_name([func_parameter[,...]])SELECT fn_search(10 );DROP FUNCTION [IF EXISTS ] sp_nameDROP FUNCTION IF EXISTS fn_search;