1 数据库三大范式
- 1NF:不可分割性,只要字段值还可以继续拆分,就不满足第一范式。不可分割性,只要字段值还可以继续拆分,就不满足第一范式。
- 2NT:在满足第一范式的前提下,主键外的每一列都必须完全依赖于主键。如果出现不完全依赖,只可能发生在联合主键的情况下。
- 3NF:在满足第二范式的前提下,除了主键列之外,其他列之间不能有传递依赖关系,即“消除冗余”,各种信息只在一个地方存储,不出现在多张表中。
2 MySQL基本命令
-- 显示所有数据库show databases;-- 创建数据库CREATE DATABASE test;-- 切换数据库use test;-- 显示数据库中的所有表show tables;-- 创建数据表CREATE TABLE pet (name VARCHAR(20), --类型要大写owner VARCHAR(20),species VARCHAR(20),sex CHAR(1),birth DATE,death DATE);-- 查看数据表结构-- describe pet;desc pet;-- 查询表SELECT * from pet;-- 插入数据INSERT INTO pet VALUES ('puffball', 'Diane', 'hamster', 'f', '1990-03-30', NULL);-- 修改数据UPDATE pet SET name = 'squirrel' where owner = 'Diane';-- 删除数据DELETE FROM pet where name = 'squirrel';-- 删除表DROP TABLE myorder;
3 select命令详解
3.1 准备练习数据
-- 创建数据库CREATE DATABASE select_test;-- 切换数据库USE select_test;-- 创建学生表CREATE TABLE student (no VARCHAR(20) PRIMARY KEY,name VARCHAR(20) NOT NULL,sex VARCHAR(10) NOT NULL,birthday DATE, -- 生日class VARCHAR(20) -- 所在班级);-- 创建教师表CREATE TABLE teacher (no VARCHAR(20) PRIMARY KEY,name VARCHAR(20) NOT NULL,sex VARCHAR(10) NOT NULL,birthday DATE,profession VARCHAR(20) NOT NULL, -- 职称department VARCHAR(20) NOT NULL -- 部门);-- 创建课程表CREATE TABLE course (no VARCHAR(20) PRIMARY KEY,name VARCHAR(20) NOT NULL,t_no VARCHAR(20) NOT NULL, -- 教师编号-- 表示该 tno 来自于 teacher 表中的 no 字段值FOREIGN KEY(t_no) REFERENCES teacher(no));-- 成绩表CREATE TABLE score (s_no VARCHAR(20) NOT NULL, -- 学生编号c_no VARCHAR(20) NOT NULL, -- 课程号degree DECIMAL, -- 成绩-- 表示该 s_no, c_no 分别来自于 student, course 表中的 no 字段值FOREIGN KEY(s_no) REFERENCES student(no),FOREIGN KEY(c_no) REFERENCES course(no),-- 设置 s_no, c_no 为联合主键PRIMARY KEY(s_no, c_no));-- 添加学生表数据INSERT INTO student VALUES('101', '曾华', '男', '1977-09-01', '95033');INSERT INTO student VALUES('102', '匡明', '男', '1975-10-02', '95031');INSERT INTO student VALUES('103', '王丽', '女', '1976-01-23', '95033');INSERT INTO student VALUES('104', '李军', '男', '1976-02-20', '95033');INSERT INTO student VALUES('105', '王芳', '女', '1975-02-10', '95031');INSERT INTO student VALUES('106', '陆军', '男', '1974-06-03', '95031');INSERT INTO student VALUES('107', '王尼玛', '男', '1976-02-20', '95033');INSERT INTO student VALUES('108', '张全蛋', '男', '1975-02-10', '95031');INSERT INTO student VALUES('109', '赵铁柱', '男', '1974-06-03', '95031');-- 添加教师表数据INSERT INTO teacher VALUES('804', '李诚', '男', '1958-12-02', '副教授', '计算机系');INSERT INTO teacher VALUES('856', '张旭', '男', '1969-03-12', '讲师', '电子工程系');INSERT INTO teacher VALUES('825', '王萍', '女', '1972-05-05', '助教', '计算机系');INSERT INTO teacher VALUES('831', '刘冰', '女', '1977-08-14', '助教', '电子工程系');-- 添加课程表数据INSERT INTO course VALUES('3-105', '计算机导论', '825');INSERT INTO course VALUES('3-245', '操作系统', '804');INSERT INTO course VALUES('6-166', '数字电路', '856');INSERT INTO course VALUES('9-888', '高等数学', '831');-- 添加添加成绩表数据INSERT INTO score VALUES('103', '3-105', '92');INSERT INTO score VALUES('103', '3-245', '86');INSERT INTO score VALUES('103', '6-166', '85');INSERT INTO score VALUES('105', '3-105', '88');INSERT INTO score VALUES('105', '3-245', '75');INSERT INTO score VALUES('105', '6-166', '79');INSERT INTO score VALUES('109', '3-105', '76');INSERT INTO score VALUES('109', '3-245', '68');INSERT INTO score VALUES('109', '6-166', '81');
3.2 select查询基本形式
```sql — 查询 student 表的所有行 SELECT * FROM student; — 查询 student 表中的指定列:name、sex 和 class SELECT name, sex, class FROM student; — 查询 teacher 表中不重复的 department 列 — DISTINCT命令: 去重查询 SELECT DISTINCT department FROM teacher;
— 查询 score 表中成绩在60-80之间的所有行(区间查询和运算符查询) — BETWEEN xx AND xx: 查询区间 SELECT FROM score WHERE degree BETWEEN 60 AND 80; SELECT FROM score WHERE degree > 60 AND degree < 80; — 查询 score 表中成绩为 85, 86 或 88 的行 — IN: 查询规定中的多个值 SELECT FROM score WHERE degree IN (85, 86, 88); — 查询 student 表中 ‘95031’ 班或性别为 ‘女’ 的所有行 — or: 表示或者关系 SELECT FROM student WHERE class = ‘95031’ or sex = ‘女’;
<a name="c1b29780"></a>## 3.3 函数计算```sql-- 查询 "95031" 班的学生人数-- COUNT: 统计计数,也可以用其他函数计算SELECT COUNT(*) FROM student WHERE class = '95031';-- AVG: 平均值SELECT AVG(degree) FROM score WHERE c_no = '3-105';-- 分组应用函数计算:先分组,后组内计算SELECT c_no, AVG(degree) FROM score GROUP BY c_no;-- 查询 score 表中的最高分的学生学号和课程编号(子查询或排序查询)。-- MAX:最大值;MIN:最小值SELECT s_no, c_no FROM score WHERE degree = (SELECT MAX(degree) FROM score);--YEAR 函数与带 IN 关键字查询--查询所有和 101 、108 号学生同年出生的 no 、name 、birthday 列select no, name, birthday from student where year(birthday) in (select year(birthday) from student where no in (101,108));--查询 student 表中每个学生的姓名和年龄select name, year(now())-year(birthday) as age from student;
3.4 排序查询
-- 以 class 降序的方式查询 student 表的所有行-- DESC: 降序,从高到低-- ASC(默认): 升序,从低到高SELECT * FROM student ORDER BY class DESC;SELECT * FROM student ORDER BY class ASC;-- 以 c_no 升序、degree 降序查询 score 表的所有行SELECT * FROM score ORDER BY c_no ASC, degree DESC;-- LIMIT r, n: 表示从第r行开始,查询n条数据SELECT s_no, c_no, degree FROM score ORDER BY degree DESC LIMIT 0, 1;-- LIMIT n offset r: 表示查询n条数据,从第r行开始SELECT s_no, c_no, degree FROM score ORDER BY degree DESC LIMIT 1 offset 3;
3.5 模糊查询
-- 查询score表中至少有 2 名学生选修,并以 3 开头的课程的平均分数-- 首先把 c_no, AVG(degree) 通过分组查询出来-- 再查询出至少有 2 名学生选修的课程-- HAVING: 表示持有-- 并且是以 3 开头的课程-- LIKE 表示模糊查询,"%" 是一个通配符,匹配 "3" 后面的任意字符。-- 把前面的SQL语句拼接起来,SELECT c_no, AVG(degree), COUNT(*) FROM score GROUP BY c_no HAVING COUNT(c_no) >= 2 AND c_no LIKE '3%';-- NOT: 取反-- LIKE: 模糊查询-- 查询 student 表中不姓 "王" 的同学记录mysql> SELECT * FROM student WHERE name NOT LIKE '王%';
3.6 多表查询
--查询所有学生的name,以及该学生在score表中对应的c_no和degree-- FROM...: 表示从 student, score 表中查询-- WHERE 的条件表示为,只有在 student.no 和 score.s_no 相等时才显示出来。SELECT name, c_no, degree FROM student, score WHERE student.no = score.s_no;--查询所有学生的 no 、课程名称 ( course 表中的 name ) 和成绩 ( score 表中的degree ) 列。-- 增加一个查询字段 name,分别从 score、course 这两个表中查询。-- as 表示取一个该字段的别名。SELECT s_no, name as c_name, degree FROM score, course WHERE score.c_no = course.no;--三表关联查询:查询所有学生的 name 、课程名 ( course 表中的 name ) 和 degree-- 由于字段名存在重复,使用 "表名.字段名 as 别名" 代替SELECT student.name as s_name, course.name as c_name, degreeFROM student, score, courseWHERE student.no = score.s_noAND score.c_no = course.no;--多重select嵌套:查询计算机系的所有课程的成绩SELECT * FROM score WHERE c_no IN (SELECT no FROM course WHERE t_no IN (SELECT no FROM teacher WHERE department = '计算机系'));
3.7 高级逻辑关键字
除了and、or、in等基本关键字,还有下面的高级关键字用于逻辑判断:
--查询计算机系与电子工程系中的不同职称的教师-- NOT: 代表逻辑非-- UNION 合并两个集SELECT * FROM teacher WHERE department = '计算机系' AND profession NOT IN (SELECT profession FROM teacher WHERE department = '电子工程系')UNIONSELECT * FROM teacher WHERE department = '电子工程系' AND profession NOT IN (SELECT profession FROM teacher WHERE department = '计算机系');--查询课程 3-105 且成绩至少高于 3-245 的 score 表-- ANY: 符合SQL语句中的任意条件。-- 也就是说,在 3-105 成绩中,只要有一个大于从 3-245 筛选出来的任意行就符合条件,-- 最后根据降序查询结果。SELECT * FROM score WHERE c_no = '3-105' AND degree > ANY(SELECT degree FROM score WHERE c_no = '3-245') ORDER BY degree DESC;--查询课程 3-105 且成绩都高于 3-245 的 score 表-- ALL: 符合SQL语句中的所有条件。-- 也就是说,在 3-105 每一行成绩中,都要大于从 3-245 筛选出来全部行才算符合条件。SELECT * FROM score WHERE c_no = '3-105' AND degree > ALL(SELECT degree FROM score WHERE c_no = '3-245');
4 Join查询
4.1 准备练习数据
CREATE DATABASE testJoin;CREATE TABLE person (id INT,name VARCHAR(20),cardId INT);CREATE TABLE card (id INT,name VARCHAR(20));INSERT INTO card VALUES (1, '饭卡'), (2, '建行卡'), (3, '农行卡'), (4, '工商卡'), (5, '邮政卡');INSERT INTO person VALUES (1, '张三', 1), (2, '李四', 3), (3, '王五', 6);
person表并没有为cardId字段设置一个在card表中对应的 id外键。如果设置了的话,person中cardId字段值为6的行就插不进去,因为该cardId值在card表中并没有。
4.2 内连接
-- INNER JOIN: 表示为内连接,将两张表拼接在一起。-- on: 表示要执行某个条件。SELECT * FROM person INNER JOIN card on person.cardId = card.id;-- 将 INNER 关键字省略掉,结果也是一样的。on 也可以改用where-- 注意:card 的整张表被连接到了右边。+------+--------+--------+------+-----------+| id | name | cardId | id | name |+------+--------+--------+------+-----------+| 1 | 张三 | 1 | 1 | 饭卡 || 2 | 李四 | 3 | 3 | 农行卡 |+------+--------+--------+------+-----------+
4.3 外连接
左外连接
完整显示左边的表 ( person ) ,右边的表如果符合条件就显示,不符合则补 NULL
-- LEFT JOIN 也叫做 LEFT OUTER JOIN,用这两种方式的查询结果是一样的。SELECT * FROM person LEFT JOIN card on person.cardId = card.id;+------+--------+--------+------+-----------+| id | name | cardId | id | name |+------+--------+--------+------+-----------+| 1 | 张三 | 1 | 1 | 饭卡 || 2 | 李四 | 3 | 3 | 农行卡 || 3 | 王五 | 6 | NULL | NULL |+------+--------+--------+------+-----------+
右外连接
完整显示右边的表 ( card ) ,左边的表如果符合条件就显示,不符合则补 NULL
SELECT * FROM person RIGHT JOIN card on person.cardId = card.id;+------+--------+--------+------+-----------+| id | name | cardId | id | name |+------+--------+--------+------+-----------+| 1 | 张三 | 1 | 1 | 饭卡 || 2 | 李四 | 3 | 3 | 农行卡 || NULL | NULL | NULL | 2 | 建行卡 || NULL | NULL | NULL | 4 | 工商卡 || NULL | NULL | NULL | 5 | 邮政卡 |+------+--------+--------+------+-----------+
全外连接
完整显示两张表的全部数据。但是MySQL不支持这种语法的全外连接,会出现错误:
-- SELECT * FROM person FULL JOIN card on person.cardId = card.id;-- 出现错误:-- ERROR 1054 (42S22): Unknown column 'person.cardId' in 'on clause'
MySQL中,应该使用 UNION 将两张表合并在一起。
