1. 数据库相关概念
DB:database
,即存储数据的仓库,它保存了一系列由组织的数据
DBMS:database management system
,数据库管理系统,数据库是通过数据库管理系统创建和操作的容器
SQL:structure query language
,结构化查询语言,用来与数据库通信的语言
2. MySQL数据库的使用
2.1 windows系统通过命令行启动mysql服务
以管理员身份打开命令行后,通过net start xxx
和net stop xxx
启动和停止mysql服务,其中xxx
表示mysql的服务名
2.2 通过命令行登录mysql客户端
- 在命令行输入
mysql -uxxx -pzzz
即可登录服务,其中xxx
表示用户名,zzz
表示密码,这种方式密码可见 - 在命令行输入
mysql -uxxx -p
,回车后再输入密码,这种方式密码不可见
3. SQL分类
- DDL:
data definition language
,数据定义语言,用来定义数据库对象,比如库、表和列等,用到关键词create
、drop
和alter
- DML:
data manipulation language
,数据库操作语言,用于定义数据库记录(数据),用到关键词insert
、update
和delete
- DCL:
data control language
,数据控制语言,用来定义访问权限和安全级别 - DQL:
data query language
,数据查询语言,用来查询记录(数据),用到关键词select
4. DQL
4.0 执行顺序
sql语句内各关键字执行是按照一定顺序进行的,具体为:
from → join → on → where → group by → having → select → order by → limit
4.1 基础查询
# 1. 查询常量
SELECT 100;
# 2. 查询表达式
SELECT 100 * 3;
# 3. 查询单个字段
SELECT last_name FROM employees;
# 4. 查询多个字段
SELECT last_name, email, employee_id FROM employees;
# 5. 查询所有字段
SELECT * FROM employees;
# 6. 查询函数(调用函数,获取返回值)
SELECT DATABASE();
SELECT VERSION();
SELECT USER();
# 7. 别名
# 方式一:使用as关键字
SELECT USER() AS 用户名;
SELECT last_name AS '姓 名' FROM employees;
# 方式二:使用空格
SELECT USER() 用户名;
SELECT last_name '姓 名' FROM employees;
# 8. mysql中+的应用
# (1). 操作数是数值类型,直接相加
SELECT 1 + 1;
# (2). 操作数是字符类型,若能转成为数值类型,则转换后继续运算
# 若不能转换为数值类型,则变为0
SELECT 1 + '2';
SELECT 1 + 'zz';
# (3). 若其中一个操作数为null,那么结果必定为null
SELECT NULL + 1;
SELECT NULL + 'zz';
# 9. 字符类型拼接
SELECT CONCAT(first_name, last_name) AS 姓名 FROM employees;
# 10. distinct关键字,去重
SELECT DISTINCT department_id FROM employees;
# 11. 查看表结构
DESC employees;
SHOW COLUMNS FROM employees;
4.2 条件查询
# 1. 按关系表达式筛选
# 关系运算符:>,<,>=,<=,=,<>,!=(不推荐)
# 查询部门编号不是100的员工信息
SELECT * FROM employees WHERE department_id <> 100;
# 查询工资小于15000的姓名、工资
SELECT last_name, salary FROM employees WHERE salary < 15000;
# 2. 按逻辑表达式筛选
# 逻辑运算符:and、or和not,也可以支持&&、||、!
# 查询部门编号不是50-100之间的员工姓名、部门编号和邮箱
SELECT last_name, department_id, email FROM employees WHERE department_id <= 50 OR department_id >= 100;
SELECT last_name, department_id, email FROM employees WHERE NOT(department_id > 50 AND department_id < 100);
# 查询奖金率大于0.03或者员工编号在60到100之间的员工信息
SELECT * FROM employees WHERE commission_pct > 0.03 OR (employee_id > 60 AND employee_id < 100);
# 3. 模糊查询
# like、in、between and、is null
# (一). like,通常和通配符搭配使用
# 常见的通配符有:
# (1). _:表示任意单个字符
# (2). %:表示任意多个字符
# 查询员工姓名中包含字符a的员工信息
SELECT * FROM employees WHERE last_name LIKE '%a%';
# 查询姓名中第三个字符为x的员工信息
SELECT * FROM employees WHERE last_name LIKE '__x%';
# 查询姓名中第二个字符为_的员工信息
SELECT * FROM employees WHERE last_name LIKE '_\_%';
SELECT * FROM employees WHERE last_name LIKE '_$_%' ESCAPE '$';
# (二). in/not in,用于查询某个字段是否属于指定的列表
# 查询部门编号是30、50或90的员工信息
SELECT * FROM employees WHERE department_id IN(30, 50, 90);
# 查询工种编号不是SH_CLERK和IT_PROG的员工信息
SELECT * FROM employees WHERE job_id NOT IN('SH_CLERK', 'IT_PROG');
# (三). between and,判断某个字段是否介于该区间
# 查询部门编号在30-90之间的员工信息
SELECT * FROM employees WHERE department_id BETWEEN 30 AND 90;
# (四). is null/is not null
# 查询没有奖金的员工信息
SELECT * FROM employees WHERE commission_pct IS NULL;
4.3 排序查询
# 排序查询
# order by
# 排序列表可以是单个字段、多个字段、表达式、函数、列数以及以上组合
# asc:升序,默认行为
# desc,降序
# 1. 按单个字段排序
# 将员工编号大于120的员工信息按照工资升序
SELECT * FROM employees WHERE employee_id > 120 ORDER BY salary;
# 2. 按表达式排序
# 对有奖金的员工姓名和年薪按照年薪降序排列
SELECT last_name, salary * 12 * (1 + IFNULL(commission_pct, 0)) AS 年薪
FROM employees WHERE commission_pct IS NOT NULL ORDER BY 年薪 DESC;
# 3. 按函数结果排序
# 按姓名的长度进行升序排序
SELECT last_name FROM employees ORDER BY LENGTH(last_name);
# 4. 按多个字段排序
# 查询员工姓名、工资、部门编号,先按照工资升序,再按照部门编号降序
SELECT last_name, salary, department_id FROM employees ORDER BY salary ASC, department_id DESC;
# 5. 按列数排序
# 查询员工信息,并以第二列升序显示
select * from employees order by 2;
4.4 函数
4.4.1 字符函数
# 1. concat 拼接字符
SELECT CONCAT('hello', first_name, last_name) 备注 FROM employees;
# 2. length 获取字符串的字节长度,使用utf8时,一个汉字占3个字节
# 输出8
SELECT LENGTH('12345李') AS 'length';
# 3. char_length 获取字符长度
# 输出6
SELECT CHAR_LENGTH('12345李');
# 4. substr 截取子串
# substr(str, 起始索引-1开始,截取字符串的长度)
# substr(str, 起始索引),截取从某个位置开始到结尾的所有
SELECT SUBSTR('1爱上了2', 2, 3);
SELECT SUBSTR('1爱上了2', 2);
# 5. instr 获取字符第一次出现的索引
SELECT INSTR('三打白骨精', '白骨精');
# 6. trim 去掉前后指定字符,默认去掉空格
SELECT LENGTH(TRIM(' 天龙八部 '));
SELECT TRIM('x' FROM 'xxxxxxx天空xx八部xxx');
# 7. lpad, rpad 左填充,右填充
SELECT LPAD('天龙八部', 10, 'a');
# 8. upper, lower 变大写,变小写
SELECT UPPER('lilili');
# 9. strcmp 比较字符大小
SELECT STRCMP('aaa', 'abc');
# 10. left, right 从左、右截取子串
SELECT LEFT('天龙八部', 1);
4.4.2 数学函数
# 1. abs 绝对值
SELECT ABS(-19);
# 2. ceil 向上取整
SELECT CEIL(-0.1);
SELECT CEIL(9.99);
# 3. floor 向下取整
SELECT FLOOR(-0.1);
# 4. round 四舍五入
SELECT ROUND(-0.5);
# 5. truncate 截取小数点后几位
SELECT TRUNCATE(1.23456, 20);
# 6. mod 取余
SELECT MOD(-10, 3);
4.4.3 日期函数
# 1. now, 输出:2020-02-25 16:27:20
SELECT NOW();
# 2. curdate, 输出:2020-02-25
SELECT CURDATE();
# 3. curtime, 输出:16:29:34
SELECT CURTIME();
# 4. datediff
SELECT DATEDIFF(NOW(), '1990-10-10');
# 5. date_formate, 格式化
SELECT DATE_FORMAT(NOW(), '%Y年%m月%d日 %H时%i分%s秒');
4.4.4 流程控制函数
# 1. if
SELECT IF(10 > 9, 1, 2);
# 2. case
# (1) case exp
# when v1 then result1
# when v2 then result2
# when v3 then result3
# else result4
# end
# 部门编号为30,工资显示为3倍,编号为40,工资显示为4倍,否者正常显示工资
SELECT department_id, last_name,
CASE department_id
WHEN 30 THEN salary * 3
WHEN 40 THEN salary * 4
ELSE salary
END AS '新工资'
FROM employees;
# (2) 类似于多重if语句,实现区间判断
# case
# when exp1 then result1
# when exp2 then result2
# when exp3 then result3
# else result4
# end
# 如果工资大于20000, 显示级别为A
# 如果工资大于15000, 显示级别为B
# 否则显示C
SELECT salary,
CASE
WHEN salary > 20000 THEN 'A'
WHEN salary > 15000 THEN 'B'
ELSE 'D'
END '级别'
FROM employees;
4.4.5 分组函数
分组函数常用于实现将一组数据进行统计计算,最终得到一个值,又称为聚合函数或统计函数
# 1. sum 求某个字段所有值的和
# 2. avg 求某个字段的平均值
# 3. max、min 求某个字段的最大值、最小值
# 4. count 计算非空字段个数
SELECT SUM(salary), AVG(salary), MIN(salary), MAX(salary), COUNT(salary) FROM employees;
4.5 分组查询
# 1. 查询每个工种的员工平均工资
SELECT job_id, AVG(salary) FROM employees GROUP BY job_id;
# 2. 每个领导的手下的人数
SELECT manager_id, COUNT(*) FROM employees WHERE manager_id IS NOT NULL GROUP BY manager_id;
# 3. 查询每个部门中员工的邮箱中包含a字符的员工最高工资
SELECT department_id, MAX(salary) FROM employees
WHERE email LIKE '%a%' AND department_id IS NOT NULL GROUP BY department_id;
# 4. 查询每个领导手下有奖金的员工的平均工资
SELECT manager_id, AVG(salary) FROM employees WHERE commission_pct IS NOT NULL GROUP BY manager_id;
# 5. 查询哪个部门的员工个数大于5
# 这道题的筛选条件为部门的员工个数大于5,也就是说要先按照部门分组,然后再筛选,
# 因此筛选条件的关键字是不能用where的,因为where关键字的执行顺序实在group by之
# 前的,因此就需要having关键字,负责分组后的条件筛选。
SELECT department_id, COUNT(employee_id) FROM employees WHERE employee_id IS NOT NULL
GROUP BY department_id HAVING COUNT(employee_id) > 5;
# 6. 每个工种有奖金的员工的最高工资大于12000的工种编号和最高工资
SELECT job_id, MAX(salary) FROM employees WHERE commission_pct IS NOT NULL
GROUP BY job_id HAVING MAX(salary) > 12000;
# 7. 领导编号大于102的每个领导手下的最低工资大于5000的领导编号和最低工资
SELECT manager_id, MIN(salary) FROM employees WHERE manager_id > 102
GROUP BY manager_id HAVING MIN(salary) > 5000;
# 8. 查询没有有奖金的员工的最高工资大于6000的工种编号和最高工资,按照最高工资升序
SELECT job_id, MAX(salary) FROM employees WHERE commission_pct IS NULL
GROUP BY job_id HAVING MAX(salary) > 6000 ORDER BY MAX(salary);
# 9. 查询每个工种、每个部门的最低工资,并按照最低工资降序
SELECT job_id, department_id, MIN(salary) FROM employees
GROUP BY job_id, department_id ORDER BY MIN(salary) DESC;
4.6 连接查询
4.6.0 概览
4.6.1 连接查询的分类
-
按功能
-
内连接
-
等值连接
-
非等值连接
-
自连接
-
-
外连接
-
左外连接
-
右外连接
-
全外连接
-
-
全连接
-
-
按年代
-
sql92:仅支持内连接
-
sql99(推荐):支持内连接、外连接(左外、右外)和交叉连接
-
4.6.2 sql92
4.6.2.1 内连接
################等值连接################
# 1. 查询员工名和部门名
SELECT last_name, department_name FROM employees emp, departments dep
WHERE emp.department_id = dep.department_id;
# 2. 查询部门编号大于100的部门名和所在的城市名
SELECT dep.department_name, loc.city FROM departments dep, locations loc
WHERE dep.location_id = loc.location_id AND dep.department_id > 100;
# 3. 查询有奖金的员工名和部门名
SELECT emp.last_name, dep.department_name FROM departments dep, employees emp
WHERE emp.commission_pct IS NOT NULL AND emp.department_id = dep.department_id;
# 4. 查询城市名中第二个字符为'o'的部门名和城市名
SELECT dep.department_name, loc.city FROM locations loc, departments dep
WHERE dep.location_id = loc.location_id AND loc.city LIKE '_o%';
# 5. 查询每个城市的部门个数
SELECT loc.city, COUNT(dep.department_id) FROM locations loc, departments dep
WHERE dep.location_id = loc.location_id GROUP BY loc.city;
# 6. 查询哪个部门的员工个数大于5,并按员工个数降序
SELECT dep.department_name, COUNT(emp.employee_id)
FROM employees emp, departments dep
WHERE emp.department_id = dep.department_id
GROUP BY emp.department_id
HAVING COUNT(emp.employee_id) > 5
ORDER BY COUNT(emp.employee_id) DESC;
4.6.3 sql99
4.6.3.1 内连接
内连接语法,新增了join
关键字,并通过on
关键字实现连接条件和筛选条件的分离
# []表示可选
select cols from table1 [inner] join table2 on join_condition where conditions
group by group_cols having group_conditions order by cols;
################等值连接################
# 1. 查询员工名和部门名
SELECT emp.last_name, dep.department_name FROM employees emp JOIN departments dep
ON emp.department_id = dep.department_id;
# 2. 查询部门编号大于100的部门名和所在的城市名
SELECT dep.department_name,loc.city FROM locations loc JOIN departments dep
ON dep.location_id = loc.location_id WHERE dep.department_id > 100;
# 3. 查询每个城市的部门个数
SELECT loc.city, COUNT(dep.department_id) FROM locations loc JOIN departments dep
ON dep.location_id = loc.location_id GROUP BY loc.city;
# 4. 查询部门中员工个数大于10的部门名,并按部门名降序
SELECT dep.department_name, COUNT(emp.employee_id) FROM employees emp JOIN departments dep
ON emp.department_id = dep.department_id GROUP BY dep.department_id HAVING COUNT(emp.employee_id) > 10
ORDER BY dep.department_name DESC;
################非等值连接################
################自连接################
# 1. 查询员工名和对应的领导名
SELECT e.last_name 员工名, l.last_name 领导名
FROM employees e JOIN employees l ON e.manager_id = l.employee_id;
4.6.3.2 外连接
查询结果为主表中的所有记录,如果从表中有匹配项,则显示匹配项;如果从表中没有匹配项,则显示null。
外连接查询一般用来查询主表中有但从表中没有的记录项,基本语法为:
- 外连接分主表和从表,且两表的顺序不能随意调换
- 左连接左表是主表
- 右连接右表是主表
# 1. 查询编号大于3的女孩的男朋友信息,有则列出,无则用null填充
SELECT beauty.*, boys.boyName FROM beauty LEFT JOIN boys
ON beauty.boyfriend_id = boys.id WHERE beauty.id > 3;
# 2. 查询哪个城市没有部门
SELECT loc.city FROM locations loc LEFT JOIN departments dep ON loc.location_id = dep.location_id
WHERE dep.department_id IS NULL;
# 3. 查询部门名为SAL或IT的员工信息
SELECT emp.last_name FROM employees emp JOIN departments dep ON emp.department_id = dep.department_id
WHERE dep.department_name = 'SAL' OR dep.department_name = 'IT';
4.7 子查询
# 1. 查询和Zlotkey相同部门的员工名和工资
SELECT emp.last_name, emp.salary FROM employees emp WHERE emp.department_id =
(SELECT emp.department_id FROM employees emp WHERE emp.last_name = 'Zlotkey');
# 2. 查询工资比公司平均工资高的员工的员工号、姓名和工资
SELECT emp.employee_id, emp.last_name, emp.salary FROM employees emp
WHERE emp.salary > (SELECT AVG(salary) FROM employees WHERE salary IS NOT NULL);
# 3. 查看location_id是1400或1700的部门中所有员工姓名
SELECT last_name FROM employees WHERE department_id IN
(SELECT department_id FROM departments WHERE location_id IN (1400, 1700));
# 4. 返回其它部门中比job_id为'IT_PROG'的部门的任一员工工资低的员工工号、姓名、job_id和工资
SELECT employee_id, last_name, job_id, salary FROM employees
WHERE salary < (SELECT MAX(salary) FROM employees WHERE job_id = 'IT_PROG')
AND job_id != 'IT_PROG';
4.8 分页查询
limit
关键字,后面接两个参数,分别是起始条目数和显示条目数,注意起始从0开始,且默认为0
# 1. 员工信息表的前5条
SELECT * FROM employees LIMIT 5;
SELECT * FROM employees LIMIT 0, 5;
# 2. 查询有奖金且工资较高的第11到第20名
SELECT * FROM employees WHERE commission_pct IS NOT NULL
ORDER BY salary DESC LIMIT 10, 10;
4.9 联合查询
当查询结果来自多张表且多张表之间没有关联,此时可以用联合查询,使用union
关键字
5. DDL
5.1 库的管理
# 1. 创建数据库
CREATE DATABASE stuDB;
CREATE DATABASE IF NOT EXISTS stuDB;
# 2. 删除数据库
DROP DATABASE stuDB;
DROP DATABASE IF EXISTS stuDB;
5.2 表的管理
5.2.1 创建表
5.2.1.1 语法规则
create table [if not exists] 表明 (
字段1 字段类型 [字段约束],
字段2 字段类型 [字段约束],
字段3 字段类型 [字段约束],
字段4 字段类型 [字段约束],
字段5 字段类型 [字段约束]
);
5.2.1.2 常用数据类型
- int:整型
- double/float:浮点型,其中double(5, 2)表示最多有5位,其中必须含有2位小数,最大可以表示999.99
- decimal:浮点型,在表示金钱方面可以使用该类型,不会出现精度缺失
- varchar:表示可变长度字符,varchar(n)根据实际存储决定开辟的空间,但最大可开辟n个字符的空间
- char:用来表示固定长度字符,char(n)不论实际存储,开辟空间都是n个字符,n可以不写,默认为1
- text:用来表示较长文本
- blob:字节类型
- date:日期类型,格式为yyyy-MM-dd
- time:时间类型,格式为hh:mm:ss
- timestamp:时间戳,格式为yyyyMMdd hhmmss,保存范围为1970-1-1 ~ 2038-12-31,占用4个字节
- datetime:时间戳,保存范围为1900-1-1 ~ xxxx,占用8个字节
varchar与char类型的区别:
varchar
是可变长度存储,char
是固定长度存储varchar
会默认额外使用1个字节来存储实际存储字符数,因此在默认情况下只能存入255个字符;当存入字符超过255时,数据库会自动使用2个字节来存储实际存储的字符数,此时最多存入的字符数变为65535;需要注意的是,数据库最多使用2个字节记录字符数,因此varchar
最多存入字符数为65535char
不会使用额外字节存储实际存入字符数量
5.2.1.3 约束
1. not null:非空约束,限制该字段为必填项
2. default:若某字段没有插入值,则自动插入默认值
3. primary key:主键,限制该字段不能重复,默认不能为空;一张表只能有一个主键,可以是多个字段的组合主键
4. unique:唯一,限制字段值不能重复
5. check:限制字段必须满足指定条件
6. foreign key:外键,限制两个表的关系,要求外键列的值必须来自主表的关联列,主、从表关联列的类型必须一致,
意思一样,但名称无要求,同时,主表的关联列必须是主键
5.2.1.4 示例
# 创建表
CREATE TABLE IF NOT EXISTS stuinfo(
stu_id INT PRIMARY KEY, # 主键约束
stu_name VARCHAR(20) UNIQUE NOT NULL, # 唯一约束、非空约束
stu_gender CHAR(1) DEFAULT '男', # 默认约束
stu_email VARCHAR(20) NOT NULL, # 非空约束
stu_age INT CHECK(age BETWEEN 0 AND 100), # 检查约束
stu_major_id INT,
CONSTRAINT fk_stuinfo_major FOREIGN KEY(stu_major_id) REFERENCES major(id) # 外键约束
);
5.2.2 修改表
5.2.2.1 语法规则
alter table 表明 add|modify|change|drop column 字段名 字段类型 [约束]
5.2.2.2 示例
# 1. 修改表名
alter table stuinfo rename to students;
# 2. 添加字段
alter table students add column birthdate timestamp not null;
# 3. 修改字段名
alter table students change column birthdate birthday datetime null;
# 4. 修改字段类型
alter table students modify column birthday timestamp;
# 5. 删除字段
alter table students drop column birthday;
5.2.3 删除表
drop table if exists students;
5.2.4 复制表
# 1. 复制表结构
create table 新表名 like 旧表名;
# 2. 复制表结构和数据
create table 新表名 select * from 表名;
# 3. 复制某个表中的某几个字段到新表中
# 原理:select语句会将oldTable中对应字段、对应字段的所有数据都会查询出来,
# 并复制到newTable中,我们只需要使select查询出来的没有数据即可,因此加上条
# 件1 = 2
create table newTable select column1, column2 from oldTable where 1 = 2;
6. DML
6.1 插入数据
# 插入语句
# 插入单行数据
insert into 表名 (column1, column2 ...) values (value1, value2 ...)
# 插入多行数据
# 这样的方式插入多行数据,只对服务器递交了单次请求
insert into 表名 (column1, column2 ...) values (value1, value2 ...), (value1, value2 ...) ...
6.2 修改数据
# 修改数据
alter table 表名 set column1 = 新值, column2 = 新值 ... where 条件
6.3 数据删除
6.3.1 示例
# 删除数据
# 1. delete,根据条件删除表中数据
delete from 表名 where 条件
# 2. truncate,删除表中所有数据
truncate table 表名
6.3.2 truncate与delete区别
- delete操作需要进行事务提交,可以做回滚,truncate操作一次性删除表中所有数据,且删除行不可恢复
- truncate操作后会返还数据所占空间,如自增长重新计数等,但delete操作不会