0. 前言 1. MySQL安装 2. 建库, 建表 3. 基础SQL语句
4. 分组查询 5. 排序 6. 分页 7. 多表查询
8. 其他杂七杂八(对于新手小白了解即可) 9. pymysql 作业:
0. 前言 数据库其实并不高深, 它就是一个能存储数据到硬盘上的一个软件. 本质就是一个软件. 数据库承载了我们目前市面上能见到的绝大多数的软件最底层的数据支持. 可以这么说. 如果没有数据, 就没有目前互联网的高速发展. 而数据库作为承载数据的载体. 它的地位也是非常高的. 数据库的分类: 早期, 数据库分为层次型数据库, 网络型数据库和关系型数据库, 在今天的互联网高速发展下, 数据库被分为关系型数据库和非关系型数据库. 关系型数据库 关系型数据库把复杂的数据逻辑归纳为二元结构(二维表格结构), 并且, 表格与表格之间可以互相的关联. 让数据的存储和查询都变得更加合理简单. 常见的关系型数据库:
非关系型数据库 非关系型数据库也被称为NoSql. 首先, SQL是我们操作数据库的编程语言. 专门为数据库而设计的. NoSql表示Not Only SQL, NoSQL的产生不是说彻底否定关系型数据库的存在, 而是对常见的关系型数据库进行补充. 目的是更好的为应用程序提供数据支撑. 传统的关系型数据库在遇到高并发, 大量数据IO请求的时候会显得力不从心. 此时NoSQL就派上用场了. 主旨是更快的为应用提供数据. 承载更多的并发. 常见的非关系型数据:
我们前期的重点在mysql上. 原因有
1. MySQL安装 mysql是一个小型的DBMS, 但是麻雀虽小, 五脏俱全. 各种大型数据库的操作MySQL都有, 首先, 我们来安装一下MySQL. 首先, 去官网下载MySQL 不同平台有不同的安装方案: windows: https://dev./downloads/installer/ 下面是安装windows需要的插件 装完了. 配置一下下环境变量 把上面那个路径扔到path里面 确定, 一路保存确认就可以了. 很easy好吧. 测试: 打开cmd. 输入命令: mysql -u root -p 回车之后, 输入密码. 最终见到以下内容, 视为没毛病 navicat安装: 激活过程自己想办法吧.... 2. 建库, 建表 数据库系统包括:
DDL: 数据定义语句 1. 创建数据库, 在mysql中, 保存数据最大的单位就是数据库. 一般中小型项目都是一个项目一个数据库. 如果遇见大型项目, 单一的数据库可能就撑不住前端的数据量了. 此时可能会涉及到多数据库设计. 我们刚入门, 先学习但数据库操作. -- 创建数据库 -- CREATE DATABASE 数据库名; -- 创建数据库, 指定字符集 CREATE DATABASE IF NOT EXISTS 数据库名 DEFAULT CHARSET UTF8mb4; -- 删除数据库 DROP DATABASE IF EXISTS 数据库名; 2. 表操作. 关系型数据库使用二维表的形式来存储数据. 就像Excel差不多. 有行和列. 创建表的时候我们要指定每一列的含义, 也就是列名, 在后面使用的时候. 数据是以行为单位进行查询的. 然后从行内拿到你想要获取的列. 就拿到你想要的数据了 -- 建表语句 CREATE TABLE IF NOT EXISTS 表名( 列名 类型(长度) 约束, 列名 类型(长度) 约束 ); 类型: 数字一般用int, 还有bit, long等, 但用的不多 字符串: char, varchar. 其中char表示定长的列. varchar表示不定长的列 char(32) 如果你只存储一个字母. 占用的空间也是32个 varchar(32) 如果值存储一个字母, 你可以认为就占用1个位置. 时间: date 年月日 time 小时分钟秒 datetime 年月日, 时分秒 小数: float 单精度小数 double 双精度小数 decimal 小数-> 精度可以自己进行设定. 精度高, 误差小 约束: 主键约束: 可以唯一的表示一条数据, 我们可以使用主键来确定具体的某个人. 就像我们生活中的身份证号, 通过身份证号可以唯一的确定一个人. 通常我们都是使用主键自增来维护主键. 语法: primary key 主键自增: 在添加数据的时候. 主键不需要给出具体的值. 由mysql自动来维护这个字段, 自动的在原有的数据基础上+1. 语法: AUTO_INCREMENT 非空约束: 设置该列是否可以为空 语法: null 或者 not null 默认值: 在没有数据的情况下, 可以给出默认值 default 值 唯一性约束: unique -- 建表语句 CREATE TABLE IF NOT EXISTS stu( id int(6) primary key AUTO_INCREMENT, name varchar(100) not null, age int(5) default 0 COMMENT '年龄', birthday date, salary decimal(10, 2) default 0.0, sno int(5) unique, phone char(11) not null unique ); -- 删除表 DROP TABLE IF EXISTS stu; -- 修改表字段信息 -- 添加新字段 ALTER TABLE stu add address VARCHAR(200); -- 删除字段 ALTER TABLE stu DROP COLUMN address; -- 修改字段类型 ALTER TABLE stu MODIFY sno varchar(32) unique not null; 3. 基础SQL语句 1. 增加 语法: insert into 表(字段1, 字段2, 字段3....) values(值1, 值2, 值3....) -- 添加数据 insert into person(name, age, phone) values('牛魔王', 88, '19812345678'); -- 一次性添加多条数据 insert into person(name, age, phone) values ('小钻风1',22, '18811112221'), ('小钻风2',22, '18811112222'), ('小钻风3',22, '18811112223'), ('小钻风4',22, '18811112224'); 2. 修改 语法: update 表 set 字段1 = 值1, 字段2 = 值2, 字段3 = 值3 ..... where 条件 -- 修改数据 update person set name = '唐僧', age = 29, phone='14722223333' where id = '5'; 3. 删除 语法: delete from table where 条件 注意: 必须加条件, 否则全表删除 -- 删除数据 delete from person; -- 全表删除. 慎用 delete from person where id = 3; -- 删除id=3的数据 delete from person where name = '小钻风1'; -- 删除名字叫小钻风1的数据 delete from person where name like '小钻风%'; -- 删除名字以小钻风开头的数据 like表示模糊查找, 小钻风% 表示以小钻风开头 4. 查询 select *|[distinct]字段1, 字段2, 字段3... from 表 where 条件 [group by] [having] [order by] -- 查询出person表中的所有数据 select * from person; -- 查询部分字段 select id, name, age from person; -- 给查询出来的数据进行重命名 select id as '主键ID', name as '名字', age as '年龄' from person; 上条件: -- 查询出年龄大于20岁的人 select * from person where age > 20; -- 查询电话号是14722223333的人 select * from person where phone = '14722223333'; -- 查询年龄是空的人 select * from person where age is null; -- 年龄在20和22之间的人 select * from person where age BETWEEN 20 and 22; -- 查询手机号是13778787878,14722223333,18811111111的人 select * from person where phone in (13778787878,14722223333,18811111111); -- 多个where条件, 可以使用and, or进行连接 -- 查询年龄大于19 手机号以14开头的人 select * from person where age > 19 and phone like '14%'; -- 查询年龄大于20 或者名字是唐僧的人 select * from person where age > 20 or name = '唐僧'; 4. 分组查询 分组查询: 按组进行查询, 分组需要使用group by语句 -- 分组查询. -- 根据名字和年龄进行分组. select age, name from person group by age, name;
-- 聚合函数 -- 查询所有人的平均年龄 select avg(age) from person -- 查询每个班级的平均年龄 select cls, avg(age) from person group by cls; -- 查询每个班的人数 select cls, count(id) from person group by cls; -- 查询每个班级年龄最大的学生 select cls, max(age) from person group by cls; -- 查询每个班级年龄最小的学生 select cls, min(age) from person group by cls; -- 查询每个班级的年龄总和 select cls, sum(age) from person group by cls; 使用having子句可以对分组查询之后的结果进行筛选. -- 查询平均年龄大有20的班级信息 select cls, avg(age) from person group by cls having avg(age) > 20; having和where都可以做数据的筛选. 区别是: where是在原始数据上进行数据筛选 having是在分组计算之后的结果进行筛选. 它们起作用的时机是不一样的 5. 排序 使用order by子句可以完成数据的排序工作 -- 按照年龄的从小到大排序 select * from person order by age; select * from person order by age asc; -- 按照年龄的从大到小排序 select * from person order by age desc; 6. 分页 -- 分页查询 select * from student limit 0, 10 -- 从第0条开始查询, 查询10条数据 select * from student limit 10, 10 -- 从第10条开始查询, 查询10条数据 -- 查询第n页数据 select * from student limit (n-1)*pageSize, pageSize; 7. 多表查询 首先, 在一个项目里肯定不能都把数据放在一张表里. 比如, 我们把员工信息都存放在一张表里: 大家观察一下. 员工信息没问题. 但是员工相应的部门信息就有大量的数据冗余. 如果一直用这样的数据来保存数据. 那么冗余的数据会占用大量的硬盘存储空间. 数据库的利用率就变的很低. 所以此时我们要考虑. 把部门信息单独的拿到另一张表里. 然后把部门表的主键引入到员工表里. 这样从结构和逻辑上讲, 效果是一样的. 但是存储空间就会节省很多. 分表:
这样, 我们通过查询员工表信息就能知道员工的deptId, 再通过deptId,到部门表就能找到该员工对应的部门信息. 最终查询出的数据是一致的. OK, 分表结束了. 但是, 这里我们必须要保证员工表中的deptId的数据来源必须是部门表. 如果deptId是胡乱填写的. 那该员工的部门信息就是错误的. 为了保证数据的一致性和安全性. 我们此时需要对deptId这一列数据进行约束. 该约束被称为外键约束. 外键约束: 某字段的数据值来源必须来自于xxx表的xxx字段. 通常我们都是把另一张表的主键拿到当前表来做外键. 在本案例中, 我们就可以把部门表的id拿到员工表中做外键. 外键的名字叫deptId create table dept( id int(10) primary key auto_increment, deptName VARCHAR(200), deptLeader VARCHAR(200), deptDesc VARCHAR(200) ); -- 然后创建employee表, 并添加外键 CREATE TABLE employee ( id int(10) primary key auto_increment, name varchar(60), age int(3), deptId int(10), constraint fk_emp_dept_id FOREIGN KEY (deptId) REFERENCES dept(id) # 添加外键约束 ); 多表联合查询: 1. 子查询 -- 子查询 -- 查询'明教'的员工信息 select * from employee where deptId in ( select id from dept where dept.deptName = '明教' ); -- 查询员工和部门的全部信息 select * from employee, dept where employee.deptId = dept.id; -- 查询'峨眉派'的平均工资 select avg(salary), deptName from employee, dept where deptId in ( select dept.id from dept where deptName = '峨眉派' ) and employee.deptId = dept.id group by deptName; 2. 关联查询 在sql语句中. 还有一种语法可以让两张甚至多张表进行关联查询. 1. inner join 内连接 2. left join 左连 3. right join 右连 select * from A xxx join B on A.字段1 = b.字段2 表示: A表和B表链接. 通过A表的字段1和b表的字段2进行连接. 通常on后面的都是主外键关系 -- 查询员工和部门的全部信息 -- 内连接 select * from employee inner join dept on employee.deptId = dept.id; -- 左联 select * from employee left join dept on employee.deptId = dept.id; -- 右联 select * from employee right join dept on employee.deptId = dept.id; 8. 其他杂七杂八(对于新手小白了解即可) 索引. 当我们的数据量很大的时候. 查询的速度会明显的下降. 尤其涉及到全表检索的时候, 此时查询效率会低到令人发指. 在数据库系统中, 可以通过添加索引来加快查询的速度.
-- 创建索引 create index student_name_index on student(sname); -- 删除索引 drop index student_name_index on student; 当我们遇见复杂的sql语句的时候. 我们可以把一部分查询的结果(sql) 保存在视图. 方便后面查询的时候可以简化sql语句. -- 创建视图 create view my_view as select sname, score from student s inner join sc on s.sid = sc.sid -- 使用视图来查询数据 select * from my_view; -- 删除视图 drop view my_view; 注意: 视图只是简化查询的sql语句. 并不能提高性能. 也就是说以上代码和不适用视图的查询效率是一致的. 触发器: 在执行某些操作的时候, 去执行一些其他的操作 例如: 假设, 我们现在要删除一些数据库中的数据. 很容易, 写个delete语句就OK了. 但是, 如果过了1个小时之后, 我们突然发现删除的数据是有用的. 想要恢复回来. 此时如果没有任何的备份和日志存在的话, 几乎是不可能的. 那怎么办? 我们可以在删除数据之前, 把要删除的数据备份出来. 保存在另一张表中. 万一要恢复的话. 直接从另一张表里就可以把数据读取出来. 防止数据丢失. 但, 此时如果我们每次执行一条删除语句之前都要多写一个插入语句的话. 就会显得很繁琐. 此时我们可以把这个工作交给触发器来完成. 当触发器设置好之后. 一旦有人删除数据. 就可以自动的把你的数据保存起来. CREATE TRIGGER 名字 BEFORE|AFTER INSERT|DELETE|UPDATE ON 表 FOR EACH ROW BEGIN sql END; -- 创建触发器 CREATE TRIGGER trigger_student_del BEFORE DELETE ON student FOR EACH ROW BEGIN insert into student_backup(sname, sage, ssex) values (old.sname, old.sage, old.ssex); END; -- 删除学生信息 delete from student where sid = 3 -- 查看 select * from student; select * from student_backup; -- 删除触发器 drop trigger trigger_student_del; old在触发器里表示要删除的旧数据. 也可以认为是现在目前数据库中的数据, 在删除的时候拿到的就是old new表示新数据. 即. 即将进入数据库的数据. 在新增的时候拿到的就是new 在修改数据的时候, 原来的数据用old表示, 新数据用new来表示 9. pymysql 1. 安装pymysql pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pymysql 2. 使用pymysql 完成数据库连接 import pymysql from pymysql.cursors import DictCursor # 连接数据库 db = pymysql.connect('127.0.0.1', 'root', 'test123456', 'homework') # 获取游标 cursor = db.cursor(DictCursor) # 结果保存在字典中. 默认保存在元组中 # 执行sql cursor.execute('select version()') # 执行sql语句 # 拿到结果 print(cursor.fetchone()) # 拿一个结果 print(cursor.fetchall()) # 拿出所有结果 print(cursor.fetchmany(10)) # 拿出n个数据 3. 使用pymysql完成各种数据库操作(增删改) import pymysql from pymysql.cursors import DictCursor # 连接数据库 db = pymysql.connect('127.0.0.1', 'root', 'test123456', 'homework') cursor = db.cursor(DictCursor) try: sql = 'INSERT INTO student(sname, sage, ssex) VALUE ('马虎疼', 18, 1)' cursor.execute(sql) db.commit() # 提交事务. 保证数据没问题 except Exception as e: db.rollback() # 事务回滚. 回到原来状态 print(e) finally: cursor.close() # 关闭游标 db.close() # 关闭链接 4. 查询操作 import pymysql from pymysql.cursors import DictCursor db = pymysql.connect('127.0.0.1', 'root', 'test123456', 'homework') cursor = db.cursor(DictCursor) sql = 'select * from student' cursor.execute(sql) # lst = cursor.fetchall() # 获取查询结果 # print(lst) for row in cursor: # 直接循环出结果 print(row) 5. sql注入以及未来写sql的注意事项 import pymysql from pymysql.cursors import DictCursor db = pymysql.connect('127.0.0.1', 'root', 'test123456', 'homework') cursor = db.cursor(DictCursor) username = input('请输入用户名:') password = input('请输入密码:') sql = f'select * from user where username = '{username}' and password = '{password}'' cursor.execute(sql) one = cursor.fetchone() if one: print('登录成功') else: print('登录失败') 输入密码的时候搞点儿事情 请输入用户名:alex 请输入密码:1' or '1'='1 登录成功 神奇的一幕出现了, 为什么会这样呢? 我们把sql拼接出来就知道咋回事儿了 select * from user where username = 'alex' and password = '1' or '1'='1' 注意看最后的条件 1 = 1 百分之百是成立的. 所以. 任何账户都能登录成功. 所以. 这样的操作是有问题的. 那如何避免呢? 使用预处理方式就可以有效的屏蔽掉sql注入 import pymysql from pymysql.cursors import DictCursor db = pymysql.connect('127.0.0.1', 'root', 'test123456', 'homework') cursor = db.cursor(DictCursor) username = input('请输入用户名:') password = input('请输入密码:') sql = 'select * from user where username = %(username)s and password = %(password)s' cursor.execute(sql, {'username': username, 'password': password}) one = cursor.fetchone() if one: print('登录成功') else: print('登录失败') 为防止sql注入, 以后写sql. 尽量这么写. 作业: 1. 基本SQL语句(慢慢做, 做一个月) 每个学生可以学习多门课程, 并且, 每一门课程都有得分. 每一门课程都有老师来教. 一个老师可以教多个学生. 看题:
初始化数据: DROP DATABASE IF EXISTS `homework`; CREATE DATABASE `homework`; USE `homework`; SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for course -- ---------------------------- DROP TABLE IF EXISTS `course`; CREATE TABLE `course` ( `cid` int(3) NOT NULL PRIMARY KEY AUTO_INCREMENT, `cname` varchar(10) DEFAULT NULL, `tid` int(3) DEFAULT NULL, KEY `fk` (`tid`), CONSTRAINT `fk` FOREIGN KEY (`tid`) REFERENCES `teacher` (`tid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for sc -- ---------------------------- DROP TABLE IF EXISTS `sc`; CREATE TABLE `sc` ( `sid` int(3) DEFAULT NULL, `cid` int(3) DEFAULT NULL, `score` int(3) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for student -- ---------------------------- DROP TABLE IF EXISTS `student`; CREATE TABLE `student` ( `sid` int(3) NOT NULL PRIMARY KEY AUTO_INCREMENT, `sname` varchar(30) DEFAULT NULL, `sage` int(3) DEFAULT NULL, `ssex` int(3) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for teacher -- ---------------------------- DROP TABLE IF EXISTS `teacher`; CREATE TABLE `teacher` ( `tid` int(3) NOT NULL PRIMARY KEY AUTO_INCREMENT, `tname` varchar(10) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records -- ---------------------------- INSERT INTO `course` VALUES ('1', '吃饭', '1'); INSERT INTO `course` VALUES ('2', '睡觉', '1'); INSERT INTO `course` VALUES ('3', '八股', '2'); INSERT INTO `course` VALUES ('4', '读书', '2'); INSERT INTO `course` VALUES ('5', '混', '2'); INSERT INTO `course` VALUES ('6', '听歌', '2'); INSERT INTO `sc` VALUES ('1', '1', '50'); INSERT INTO `sc` VALUES ('1', '2', '50'); INSERT INTO `sc` VALUES ('1', '3', '30'); INSERT INTO `sc` VALUES ('1', '4', '80'); INSERT INTO `sc` VALUES ('1', '5', '10'); INSERT INTO `sc` VALUES ('2', '1', '70'); INSERT INTO `sc` VALUES ('2', '2', '55'); INSERT INTO `sc` VALUES ('2', '3', '35'); INSERT INTO `sc` VALUES ('2', '4', '95'); INSERT INTO `sc` VALUES ('2', '5', '78'); INSERT INTO `sc` VALUES ('3', '1', '55'); INSERT INTO `sc` VALUES ('3', '2', '85'); INSERT INTO `sc` VALUES ('3', '3', '74'); INSERT INTO `sc` VALUES ('3', '4', '47'); INSERT INTO `sc` VALUES ('3', '5', '61'); INSERT INTO `sc` VALUES ('4', '1', '55'); INSERT INTO `sc` VALUES ('4', '2', '87'); INSERT INTO `sc` VALUES ('4', '3', '85'); INSERT INTO `sc` VALUES ('4', '4', '76'); INSERT INTO `sc` VALUES ('4', '5', '87'); INSERT INTO `sc` VALUES ('5', '1', '55'); INSERT INTO `sc` VALUES ('5', '2', '5'); INSERT INTO `sc` VALUES ('5', '3', '3'); INSERT INTO `sc` VALUES ('5', '4', '34'); INSERT INTO `sc` VALUES ('5', '5', '40'); INSERT INTO `sc` VALUES ('6', '1', '100'); INSERT INTO `sc` VALUES ('6', '2', '100'); INSERT INTO `sc` VALUES ('6', '3', '100'); INSERT INTO `sc` VALUES ('6', '4', '75'); INSERT INTO `sc` VALUES ('6', '5', '71'); INSERT INTO `sc` VALUES ('7', '3', '50'); INSERT INTO `sc` VALUES ('7', '4', '55'); INSERT INTO `sc` VALUES ('7', '5', '47'); INSERT INTO `sc` VALUES ('8', '6', '50'); INSERT INTO `sc` VALUES ('9', '6', '55'); INSERT INTO `student` VALUES ('1', '朱元璋', '10', '1'); INSERT INTO `student` VALUES ('2', '朱棣', '20', '1'); INSERT INTO `student` VALUES ('3', '朱高炽', '20', '1'); INSERT INTO `student` VALUES ('4', '朱瞻基', '50', '1'); INSERT INTO `student` VALUES ('5', '万贵妃', '55', '2'); INSERT INTO `student` VALUES ('6', '慈禧', '50', '2'); INSERT INTO `student` VALUES ('7', '小郭子', '40', '1'); INSERT INTO `student` VALUES ('8', '于谦', '55', '1'); INSERT INTO `student` VALUES ('9', '猴哥', '5', '1'); INSERT INTO `teacher` VALUES ('1', '黄观'); INSERT INTO `teacher` VALUES ('2', '商洛'); 2. 使用pymysql完成业务线系统开发. 表关系: 管理员表: ID 用户名 密码 邮箱 业务线: ID 名称 主机表: ID 主机名 密码 业务线ID 需求: 用户登录(密码基于md5且加盐) 业务线管理: 添加业务线 删除业务线 修改业务线 查看业务线 主机管理(含外键): 添加主机 删除主机 修改主机 查看主机
|
|
来自: O听_海_轩O > 《Python基础入门讲解》