当前位置:   article > 正文

windows,pycharm,python,PyMySQL,mysql及应用案例

windows,pycharm,python,PyMySQL,mysql及应用案例

1.下载安装Mysql

1.1 安装mysql57

下载Mysql5.7,暂不使用8.0版本:https://downloads.mysql.com/archives/community/
mysql-5.7.40-winx64.zip
解压到C:\Program Files\,这代表将mysql安装在这个位置
在C:\Program Files\mysql-5.7.40-winx64下新建:my.ini文件
  1. [mysqld]
  2. #端口
  3. port=3306
  4. #mysql的安装目录
  5. basedir=C:\\Program Files\\mysql-5.7.40-winx64
  6. #mysql的data目录
  7. datadir=C:\\Program Files\\mysql-5.7.40-winx64\\data
在终端中:
1,初始化mysql
"C:\Program Files\mysql-5.7.40-winx64\bin\mysqld.exe" --initialize-insecure
2,将mysql制作成windows服务
"C:\Program Files\mysql-5.7.40-winx64\bin\mysqld.exe" --install mysql57
3,启动mysql服务
net start mysql57
4,关闭mysql服务
net stop mysql57

1.2 测试mysql57

1,连接mysql:注意,这里使用的是mysql.exe而非mysqld.exe
"C:\Program Files\mysql-5.7.40-winx64\bin\mysql.exe" -h 127.0.0.1 -P 3306 -u root -p
2,默认是空密码,直接enter;
3,显示当前的数据库
show databases;
4,退出mysql
exit;

1.3 修改密码

1,设置密码:进入mysql后:
set password = password("123456")
则密码设置成功;
2,忘记密码:
1)在my.ini中增加一行:
skip-grant-tables=1
2)重启mysql,则可以不用密码登录
net stop mysql57
net start mysql57
3)进入mysql
"C:\Program Files\mysql-5.7.40-winx64\bin\mysql.exe" -h 127.0.0.1 -P 3306 -u root -p
3)按照步骤1设置密码;
4)删除my.ini中增加的skip-grant-tables=1

1.4 卸载mysql57

1,删除mysql57服务
"C:\Program Files\mysql-5.7.40-winx64\bin\mysqld.exe" --remove mysql57
2,删除mysql57目录

2. 安装配置pycharm

2.1 安装pycharm

略,参考相关教程

2.2 创建工程

略,参考相关教程

2.2 配置pycharm以使用PyMySQL

file -> settings -> project:xx -> python interpreter
即可新建python文件并使用PyMySQL了

3. MySQL基础

3.1 MySQL数据类型

int

int :有符号,取值范围:-2147483648 ~ -2147483647
int unsigned: 无符号取值范围0~ 4294967295
int(5)zerofill:很少使用,仅用于显示

tinyint

使用方法与int一样,但数据范围为-128~127,0~255

bigint

使用方法与int一样,但数据范围为-9223372036854775808~9223372036854775807,0~1844674407379551615

decimal [m[,d]] [unsigned] [zerofill]

m:数字总数(符号不算),最大值65
d:小数点后个数,最大值30
decimal(8,2):数字总体为8位,小数点后保留2位,小数超出时会4舍5入,整数位超出时会报错

float [m[,d]] [unsigned] [zerofill]

单精度浮点数,非精准小数,不常用

double [m[,d]] [unsigned] [zerofill]

双精度浮点数,非精准小数值,不常用

char(m)

定长字符,m代表字符串长度,最多配置位255个字符,字符不够时补充空格为m个字符,字符超出时会报错

varchar(m)

变长字符,m代表字符串长度,最多容纳65535个字符,字符不够时按照真实长度存储,字符超出时会报错

text

保存变长大字符串,一般用于文章或新闻,最长可到65535(2**16-1)个字符

mediumtext

最长可到16777215(2**24-1)个字符

longtext

最长可到4GB(2**32-1)个字符

datetime

YYYY-MM-DD:HH:MM:SS(1000-01-01 00:00:00 / 9999-12-31 23:59:59)
客户端存入的时间时不作改变,原样输入和输出。常用。

timestamp

YYYY-MM-DD:HH:MM:SS(1970-01-01 00:00:00 / 2037)
客户端存入的时间时,从当前时区转化为UTC(世界标准时间)进行存储,查询时有将其转化为客户端当前时区进行返回。不常用。

date

YYYY-MM-DD(1000-01-01 / 9999-12-31)

time

HH:MM:SS(-838:59:59 / 838:59:59)

3.2 表的关系

单表:单独一张保存信息的
一对多:两张表存储信息,且两张表存在一对多或多对一的关系
多对多:需要三张表来存储信息,两张表 + 关系表,创造出两个单表之间多对多关系
为建立表的关系,需要使用外键来建立约束

4. 使用PyMySQL操作数据库

4.1 连接数据库connect()

  1. import pymysql
  2. # 连接数据库
  3. conn = pymysql.connect(host='127.0.0.1',port=3306,user='root',charset='utf8',password="123456")
  4. cursor = conn.cursor()

4.2创建数据库和表

  1. #1.创建数据库,charset编码规则,collate排序规则
  2. cursor.execute("create database db1 default charset utf8 collate utf8_general_ci")
  3. #查询不需要commit(),增删改需要commit()
  4. conn.commit()
  5. #2.进入数据库创建表,并查看
  6. cursor.execute("use db1")
  7. sq1 = """
  8. create table L1(
  9. id int not null primary key auto_increment,
  10. title varchar(128),
  11. content text,
  12. ctime datetime
  13. )default charset=utf8;
  14. """
  15. cursor.execute(sq1)
  16. conn.commit()

4.2-补1:创建数据表时的关键字

  1. create table L1(
  2. id int primary key auto_increment,    --primary key主键,不允许为空,不能重复
  3.                                           --auto_increment自增
  4.                                         --一张表只能有一个主键,一个自增列,自增列一般为主键
  5. name varchar(16) not null.            --不允许为空
  6.     email varchar(32) null,            --允许为空
  7.     age int default 3                     --默认值为3
  8.    
  9. )default charset=utf8;

4.2-补2:关联表时的外键

1,外键是一种索引,是通过一张表中的一列指向另一张表的 主键,使得这两张表产生关联
2,外键可以在创建表时添加,也可以后续使用alter table 表名 add constraint ......来添加;
3,外键也可通过alter table 表名 drop foreign key ....来删除
4,有多张表时,关系表需要有多个外键约束
参考: MySQL外键(详解)
参考: sql_外键

4.3 查看数据库和表,以及表的内容

  1. # 查看数据库
  2. cursor.execute("show databases")
  3. result = cursor.fetchall()
  4. print(result)
  5. #进入数据库,查看数据表
  6. cursor.execute("use db1")
  7. cursor.execute("show tables")
  8. result = cursor.fetchall()
  9. print(result)
  10. #查看数据表的内容
  11. cursor.execute("desc l1")
  12. result = cursor.fetchall()
  13. print("desc:",result)
  14. #查看数据表的数据
  15. cursor.execute("select * from l1")
  16. result = cursor.fetchall()
  17. print("select:",result)

4.4删除数据库和表,清空表

  1. #删除数据库
  2. cursor.execute("drop database db1")
  3. conn.commit()
  4. #删除数据表
  5. cursor.execute("use db1")
  6. cursor.execute("drop table l1")
  7. conn.commit()
  8. #清空数据表
  9. cursor.execute("delete from l1")   
  10. 或:
  11. cursor.execute("truncate table l1")    --速度快,但无法回滚和撤销

4.5修改表

添加列

alter table 表名 add 列名 类型 [其他关键字];

删除列

alter table 表名 drop column 列名 类型;

修改类的类型

alter table 表名 modify column 列名 类型;

修改列名和类型

alter table 表名 change 原列名 新列名 新类型;

修改列默认值

alter table 表名 alter 列名 set default 默认值;

删除列默认值

alter table 表名 alter 列名 drop default;

4.6 数据行增删改查

新增数据:

  1. insert into 表名 (列名,列名,...,列名) values(值,值,...,值)
  2. insert into 表名 (列名,列名,...,列名) values(值,值,...,值),(值,值,...,值) --插入多行数据
  3. insert into 表名 values(值,值,值),(值,值,值)    --如果插入值的个数和列的个数相同,则可以不写列名

删除数据

  1. delete from 表名    --删除表里的所有数据
  2. delete from 表名 where 条件    --按条件删除
  3. 例1:delete from tb1 where name="sdd"
  4. 例2:delete from tb1 where name='sdf' and id='123'
  5. 例3:delete from tb1 where name='sdb' or id='123'
  6. 例4:delete from tb1 where id>9

修改数据

  1. update 表名 set 列名=值
  2. update 表名 set 列名=值 where 条件
  3. 例1:update tb1 set name="sdd" where id='123' --修改id为123的行的name为sdd
  4. 例2:update tb1 set age=age+1 where id='123' --修改id为123的行的age为原有值+1
  5. 例3:update tb1 set name=concat(name,"123") where id='123' --在id为123的行的name后加上123后缀

查询数据

  1. select * from 表名        
  2. select 列名,列名,列名 from 表名           
  3. select 列名,列名 as 别名 from 表名
  4. select * from 表名 where 条件           --按条件搜索整张表
  5. select 列名,列名 from 表名 where 条件    --按条件收索指定列
  1. 例:
  2. select * from tb1
  3. select id,name from tb1
  4. select id,name,111 from tb1 --表里面没有111时,查询结果会增加一列,其值全为111
  5. select id,name,111 as age from tb1 --表里面没有111时,查询结果会增加一列,其值全为111,同时表头为age
  6. select * from tb1 where id=1
  7. select * from tb1 where id >1
  8. select * from tb1 where id!=1
  9. select * from tb1 where name="sdd" and password='123'

4.7 where语句

条件查询: SQL语句之条件查询--WHERE(where)

4.8 排序order by

参考: SQL语句之排序查询--ORDER BY

4.9 取部分及分页查询limit

参考: SQL中limit的用法
参考: sql语句中的limit n,limit n,m 和 limit m offset n

4.10 聚合函数、分组group by及having

参考: sqlserver之group by 与over函数
参考: SQL之HAVING
参考: SQL中group by的用法总结

4.11 连表 join

参考: SQL连接表(内连接、左连接、右连接、交叉连接、全外连接
一般用左外连接,较少用右外连接

可以连接多张表

4.12 上下连表union

参考: SQL UNION运算符
union会去重,union all不去重

4.13 用户授权(权限管理)

参考:MySQL查看用户权限及权限管理

用户和权限信息存储在mysql.user这张表中
查询用户和权限:SELECT user,authentication_string,host FROM mysql.user;
创建用户:create user username@ip indentified by '密码'
例如:
1)create user 'zhangsan'@'127.0.0.1' indentified by '123456' --在127.0.0.1这个ip地址上用zhangsan这个账户,用密码123456登录
2)create user 'zhangsan'@'%' indentified by '123456' --在任意ip地址上用zhangsan这个账户,用密码123456登录mysql
3)create user 'zhangsan'@'127.0.0.1' indentified by '123456' --在127.0.0.1这个ip地址上用zhangsan这个账户,用密码123456登录
删除用户:drop user 'zhangsan'@127.0.0.1
修改用户:rename user '张三'@'127.0.0.1' to 'lisi'@'128.3.12.2'
修改密码:set password for '张三'@'127.0.0.1' = password('738')
授权:grant 权限 on 数据库.表 to '用户'@'ip地址'
授权后刷新:FLUSH PRIVILEGES;
查看权限:show grants for '用户'@'ip地址'
取消授权:remoke 权限 on 数据库.表 from '用户'@'ip地址'

5. SQL数据库的导入/出

参考: Pycharm连接Mysql数据库操作、以Excel文件导入导出

6. 示例1:班级管理数据库操作

6.1 表结构

6.2 数据库操作

1创建数据库和表结构
  1. --创建和使用数据库
  2. create database db1 default charset utf8 collate utf8_general_ci;
  3. use db1;
  4. --创建表
  5. create table class(
  6. cid int not null auto_increasement primary key,
  7. caption varchar(16) not null
  8. )default charset=utf8;
  9. --添加数据
  10. insert into class values ('1','一年级一班'),('2','一年级二班'),('3','三年级一班')
  11. ......其余表(略)
2创建用户并赋予权限
  1. create user 'luffy'@'%' indentified by 'root123';
  2. grant all privileges on db1.* to 'luffy'@'%';
  3. flush privileges;
3查询'李'姓老师名单
select * from teacher where tname like '李%'
4查询男生、女生人数
select gender,count(1) from student group by gender;
5查询同名同姓学生名单,并统计同名人数
select sname,count(1) from student group by sname having count(1)>1;
6查询“三年级一班”的所有学生信息
  1. select
  2. *
  3. from
  4. student
  5. left join class on student.class_id = class.cid
  6. where class.caption='三年级一班';
7查询每个班级的班级名称、班级人数
  1. select
  2. class.caption,count(1)
  3. from
  4. student
  5. left join class on student.class_id = calss.cid
  6. group by class.caption;
8查询成绩小于60分的同学的学号、姓名、成绩、课程名称
  1. select
  2. student.sid,
  3. student.sname,
  4. score.number,
  5. course.cname
  6. from
  7. score
  8. left join student on score.student_id=student.sid
  9. left join cource on score.course_id=course.cid
  10. where number<60;
9查询选修了“生物课”的所有学生ID、学生姓名、成绩
  1. select
  2.     student.sid,
  3.     student.sname,
  4.     score.number
  5. from
  6.     score
  7.     left join student on score.student_id=student.sid
  8.     left join course on score.course_id=course.cid
  9. where
  10. course.cname='生物';
10查询选修了“生物课”且成绩低于60分的所有学生ID、学生姓名、成绩
  1. select
  2. student.sid,
  3. student.sname,
  4. score.number
  5. from
  6. score
  7. left join student on score.student_id=student.sid
  8. left join course on score.course_id=course.cid
  9. where
  10. course.cname='生物' and score.number<60;
11查询所有同学的学号、姓名、选课数、总成绩
  1. select
  2.     student_id,
  3.     student.sname,
  4.     count(1),
  5.     sum(number)
  6. from
  7.     score
  8.     left join student on score.student_id=student.sid
  9. group by student_id;

12查询各科选修学生的人数

  1. select
  2.     coourse_id,
  3.     course.cname,
  4.     count(1)
  5. from
  6.     score
  7.     left join course on course.cid=score.course_id
  8. group by course_id;
13查询各科成绩的总分、最高分、最低分,显示:课程ID、课程名称、总分、最高分、最低分
  1. select
  2.     course_id,
  3.     course.cname,
  4.     sum(number),
  5.     max(number),
  6.     min(number)
  7. from
  8.     score
  9.     left join course on score.course_id=course.cid
  10. group by course_id;
14查询各科成绩的平均分,显示:课程id、课程名称、课程平均分
  1. select
  2.     course_id,
  3.     course.cname,
  4.     avg(num)
  5. from
  6.     score
  7.     left join course on score.course_id=course.cid
  8. group by course_id;
15查询各科成绩的平均分,显示:课程id、课程名称、课程平均分(按照从大到小排队)
  1. select
  2. course_id,
  3. course.cname,
  4. avg(num) as A
  5. from
  6. score
  7. left join course on score.course_id=course.cid
  8. group by course_id
  9. order by A desc;
16 查询各科成绩 平均分和及格率,显示:课程id、课程名称、平均分、及格率
  1. select
  2.     course_id,
  3.     course.cname,
  4.     avg(num),
  5.     sum(case when score.num>60 then 1 else 0 end)/count(1)*100 as percent
  6. from
  7.     score
  8.     left join course on score.course_id=course.cid
  9. group by course_id
17查询平均成绩大于60的所有学生的学号,平均成绩
  1. select
  2.     student_id,
  3.     avg(number)
  4. from
  5.     score
  6. group by
  7.     student_id having avg(num)>60
18查询平均成绩大于85的所有学生的学号、平均成绩、姓名
  1. select
  2.     student_id,
  3.     student.sname,
  4.     avg(number)
  5. from
  6.     score
  7.     left join student on score.student_id=student.sid
  8. group by
  9.     student_id having avg(number)>=85
19 查询“二年级一班”每个学生的学号、姓名、总成绩、平均成绩
  1. select
  2.     student_id,
  3.     student.sname,
  4.     sum(number),
  5.     avg(number)
  6. from
  7.     score
  8.     left join student on score.student_id=student.sid
  9.     left join class on student.class_id=class.cid
  10. where
  11.     class.caption='二年级一班'
  12. group by
  13.     student_id

20查询各个班级的班级名称、总成绩、平均成绩、及格率(按平均成绩从大到小排序)

  1. select
  2.     class.caption,
  3.     sum(number),
  4.     avg(number) as av,
  5.     sum(case when score.num>60 then 1 else 0 end)/count(1)*100 as JG
  6. from
  7.     score
  8.     left join student on score.student_id=student.sid
  9.     left join class on student.class_id=class.cid
  10. group by
  11.     class.caption
  12. order by
  13.     av desc
21查询学过李老师课程的同学的学号和姓名
  1. select
  2.     student_id,
  3.     student.sname
  4. from
  5.     score
  6.     left join student on score.student_id=student.sid
  7.     left join course on score.course_id=course.cid
  8.     left join teacher on course.teacher_id=teacher.tid
  9. where
  10.     teacher.tname='李老师'
22查询没学过李老师课程的同学的学号和姓名
  1. select * from student where sid not in( 
  2.   select
  3.     student_id
  4.     from
  5.     score
  6.     left join student on score.student_id=student.sid
  7.     left join course on score.course_id=course.cid
  8.     left join teacher on course.teacher_id=teacher.tid
  9.     where
  10.     teacher.tname!='李老师'
  11. )
23查询选修李老师所授课程的学生中,成绩最高的学生姓名及成绩(不考虑并列)
  1. select
  2. student.sname,
  3.     number
  4. from
  5. score
  6. left join student on score.student_id=student.sid
  7. left join course on score.course_id=course.cid
  8. left join teacher on course.teacher_id=teacher.tid
  9. where
  10. teacher.tname='李老师'
  11. order by
  12.     score.number desc
  13.     limit 1
24查询选修李老师所授课程的学生中,成绩最高的学生姓名及成绩(考虑并列)
  1. select
  2. student.sname,
  3. number
  4. from
  5. score
  6. left join student on score.student_id=student.sid
  7. left join course on score.course_id=course.cid
  8. left join teacher on course.teacher_id=teacher.tid
  9. where
  10. teacher.tname='李老师'
  11. and score.number={
  12.         select
  13.             max(number)
  14.         from
  15.             score
  16.             left join course on score.course_id=course.cid
  17.             left join teacher on course.teacher_id=teacher.tid
  18.         where
  19.             teacher.tname='李老师'
  20.     }
25查询只选修了一门课的全部学生的学号、姓名
  1. select
  2.     student_id,
  3.     student.sname
  4. from
  5.     score
  6.     left join student on score.student_id=student.sid
  7. group by
  8.     student_id
  9. having
  10.     count(1)=1
26查询至少选修了2门课程的学生、学生姓名、选修课程数量
  1. select
  2. student_id,
  3. student.sname,
  4.     count(1)
  5. from
  6. score
  7. left join student on score.student_id=student.sid
  8. group by
  9. student_id
  10. having
  11.     count(1)>=2
27查询两门及以上不及格的同学的学号、姓名、选修课数量
  1. select
  2. student_id,
  3. student.sname,
  4. count(1)
  5. from
  6. score
  7. left join student on score.student_id=student.sid
  8. where
  9.     number<60
  10. group by
  11. student_id
  12. having
  13.     count(1)>=2
28查询选修了所有课程的学生的学号、姓名
  1. select
  2. student_id,
  3. student.sname
  4. from
  5. score
  6. left join student on score.student_id=student.sid
  7. group by
  8.     student_id
  9. having
  10.     count(1) = (select count(1) from course)

29查询未选修所有课程的学生的学号、姓名

  1. select
  2. student_id,
  3. student.sname
  4. from
  5. score
  6. left join student on score.student_id=student.sid
  7. group by
  8. student_id
  9. having
  10. count(1) < (select count(1) from course)
30查询所有学生都选修了的课程的课程号和课程名
  1. select
  2.     course_id,
  3.     course.cname
  4. from
  5.     score
  6.     left join course on score.course_id=course.cid
  7. group by
  8.     course_id
  9. having
  10.     count(1) = ( select count(1) from student )
31查询选修了生物和体育课程的所有学生的学号、姓名
  1. select
  2. student_id,
  3. student.sname
  4. from
  5. score
  6. left join student on score.student_id=student.sid
  7.     left join course on score.course_id=course.cid
  8. where
  9.     course.cname in ("生物","体育")
  10. group by
  11.     student_id
  12. having
  13.     count(1)=2
32查询至少有一门与学号为“1”的学生所选修的课程相同的其他学生学号和姓名
  1. select
  2. student_id,
  3. student.sname
  4. from
  5. score
  6. left join student on score.student_id=student.sid
  7. left join course on score.course_id=course.cid
  8. where
  9. score.student_id!=1 and
  10. score.course_id in ( select course_id from score where student_id=1 )
  11. group by
  12. student_id
  13. having
  14. count(1)>=1
33查询与学号为2的同学选修的课程完全相同的其他学生学号和姓名
  1. select
  2. student_id,
  3. student.sname
  4. from
  5. score
  6. left join student on score.student_id=student.sid
  7. left join course on score.course_id=course.cid
  8. where
  9. score.course_id in ( select course_id from score where student_id=1 )
  10.     and
  11.     --第二个条件为找到选修课程数量与学号为2的学生一样的id
  12.     score.student_id in(
  13.         select
  14.             student_id
  15.         from
  16.             score
  17.         where
  18.             student_id!=2
  19.         group by
  20.             student_id
  21.         having
  22.             count(1) = (select count(1) from score where student_id=2)
  23.     )
  24. group by
  25. student_id
  26. having
  27. count(1)=( select count(1) from score where student_id=2 )
34查询生物课程比物理课程高的所有学生的学号和姓名
  1. select
  2.     student_id,
  3.     student.sname,
  4.     max(case course.cname when '生物' num else -1 end) as sw,
  5.     max(case course.cname when '物理' num else -1 end) as wl
  6. form
  7.     score
  8.     left join student on score.student_id=student.sid
  9.     left join course on score.course_id=course.cid
  10. where
  11.     course.cname in ('生物','物理')
  12. group by
  13.     student_id
  14. having
  15.     sw > wl   
35查询每门课程成绩最好的前3名(不考虑成绩并列)
  1. select
  2.     cid,
  3.     cname,
  4.     --第一名
  5.     (select
  6.         student.sname
  7.     from
  8.         score
  9.         left join student on score.student_id=student.sid
  10.     where
  11.         course_id = course.id
  12.     order by
  13.         number desc
  14.     limit
  15.         1
  16.     offset
  17.         0       
  18.     ) as '第一名',
  19.     --第二名
  20. (select
  21. student.sname
  22. from
  23. score
  24. left join student on score.student_id=student.sid
  25. where
  26. course_id = course.id
  27. order by
  28. number desc
  29. limit
  30. 1
  31. offset
  32. 1
  33. ) as '第二名',
  34.     --第三名
  35. (select
  36. student.sname
  37. from
  38. score
  39. left join student on score.student_id=student.sid
  40. where
  41. course_id = course.id
  42. order by
  43. number desc
  44. limit
  45. 1
  46. offset
  47. 2
  48. ) as '第三名'
  49. from
  50.     course
  51.    
36创建一张有外键的表sc,把score的所有数据都插入到sc中
  1. create table 'sc'{
  2.     'sid' int not null auto_increment primary key,
  3.     'student_id' int not null,
  4.     'course_id' int not null,
  5.     'num' int not null,
  6.     constraint 'fk_sc_course' foreign key ('course_id') reference 'course'('cid'),
  7.     constraint 'fk_sc_student' foreign key ('student_id') reference 'student'('sid')
  8. } default charset=utf8;
  9. insert into sc select * from score;
37 向sc中插入一些记录,1)没有上过课程id为2的课程的学生id,2)课程id为2,3)成绩为80
  1. insert into sc (student_id, course_id, number)
  2. select
  3.     sid,
  4.     2,
  5.     80
  6. from
  7.     student
  8. where
  9.     sid not in (
  10.         select
  11.             student_id
  12.         from
  13.             score
  14.         where
  15.             course_id=2
  16.     )
38 向sc中插入一些记录,1)没上过id为2的课程的学生id,2)课程id为2,3)成绩为课程id为3的最高分
  1. insert into sc (student_id,course_id,number)
  2. select
  3.     sid,
  4.     2,
  5.     (select
  6.         max(num)
  7.     from
  8.         score
  9.     where
  10.         course_id=3   
  11.     ) as num
  12. from
  13.     student
  14. where
  15.     sid not in (
  16.         select
  17.             student_id
  18.         from
  19.             score
  20.         where
  21.             course_id=2
  22.     )   

7.示例2: 博客系统与索引

7.1 表结构

7.2索引

常见索引:

1,主键索引:加速查找,不能为空,不能重复,(多列) 联合主键索引
  1. create table 表名(
  2.     id int not null auto_increment,
  3.     name varchar(32) not null,
  4.     primary key(id) --主键索引
  5. );
  6. create table 表名(
  7. id int not null auto_increment,
  8. name varchar(32) not null,
  9. primary key(id,name) --多列,联合主键(不常用)
  10. );
  11. alter table 表名 add primary key(列名); -- 表创建完成后添加主键索引
  12. drop table 表名 drop primary key;
2,唯一索引:加速查找,不能重复 ,允许最大1个空(多列)联合唯一索引
  1. create table 表名(
  2. id int not null auto_increment primary key,
  3. name varchar(32) not null,
  4.     email varchar(64) not null,
  5.     unique ix_name(name)
  6. );
  7. create table 表名(
  8. id int not null auto_increment primary key,
  9. name varchar(32) not null,
  10. email varchar(64) not null,
  11. unique ix_name(name), --唯一索引,每一列的内容不能重复
  12.     unique ix_emai(email) --多个唯一索引
  13. );
  14. create table 表名(
  15. id int not null auto_increment primary key,
  16. name varchar(32) not null,
  17. email varchar(64) not null,
  18. unique ix_group1(name,email) --多列,联合唯一索引,多列的内容,可以有一部分重复,但不能完全重复
  19. );
  20. create unique index 索引名 on 表名(列名);
  21. drop unique index 索引名 on 表名
3,普通索引:加速查找 (多列)联合索引
  1. create table 表名(
  2. id int not null auto_increment primary key,
  3. name varchar(32) not null,
  4. email varchar(64) not null,
  5. index ix_name(name)
  6. );
  7. create table 表名(
  8. id int not null auto_increment primary key,
  9. name varchar(32) not null,
  10. email varchar(64) not null,
  11. index ix_name(name), --索引
  12. index ix_emai(email) --多个索引
  13. );
  14. create table 表名(
  15. id int not null auto_increment primary key,
  16. name varchar(32) not null,
  17. email varchar(64) not null,
  18. index ix_group1 (name,email) --多列,联合索引
  19. );
  20. create index 索引名 on 表名(列名);
  21. drop index 索引名 on 表名

7.3索引不命中的情况

1,类型不一致
  1. select * from tb1 where name=123 --未命中,效率低,因为表中name为字符串型
  2. 但主键索引类型不一致时不影响效率
2,使用不等于
  1. select * from tb1 where name!='123' --未命中,效率低,因为使用了不等于
  2. 但主键索引使用不等于时不影响效率
3,or,当or条件中与未建立索引的列
select * from tb1 where name!='123' or password="xsd"  --如果password未建立索引,则效率低
4,排序,根据索引排序时,选择的映射如果不是索引,则不走索引
  1. select * from tb1 order by name --即使name建立了索引,也无法命中,因为选择的是*
  2. 但使用主键order by时不受影响
5,like,模糊匹配时通配符在前面或中间
  1. select * from tb1 where name like '%uuu' --未命中
  2. select * from tb1 where name like '__uuu' --未命中
  3. select * from tb1 where name like 'u%-_uu' --未命中
  4. select * from tb1 where name like 'uuu%' --命中
  5. select * from tb1 where name like 'uuu_' --命中
6,使用mysql内置函数时
  1. select * from tb1 where reverse(name)='asdlf' --未命中
  2. 但对条件使用内置函数时命中
  3. select * from tb1 where name=reverse('asdfj') --命中
7,联合索引,应遵循最左前缀
  1. 如果联合索引为(name,password)
  2. select * from tb1 where name='122' and password='233' --命中
  3. select * from tb1 where name='122' --命中
  4. select * from tb1 where password='233' --未命中
  5. select * from tb1 where name='122' or password='233' --未命中

7.4 索引 执行计划

在查询语句前,加explain,查看返回数据的type列。如果结果是all,则查询速度最低;如果结果是system/const,则查询速度最快;排序为all<index<range<index_merge<ref_or_null<ref<eq_ref<system/const

7.5博客系统 表索引 设计

对于推荐表:
1)id为主键索引;
2)user_id和article_id可以设计为联合唯一索引,因为用户只能评价一篇文章一次。
对于用户表:
1)id为主键索引;
2)用户名+密码,设计为联合索引,加快搜索进度;
3)手机号:唯一索引,因为不能重复;
4)邮箱:唯一索引,不能重复。

8.示例3:MySQL函数

8.1 内置函数

  1. count()
  2. max()
  3. min()
  4. avg()
  5. reverse()
  6. concat()
  7. now()--获取当前时间
  8. date_format(now(),'%Y-%m-%d %H:%m:%s')--按格式格式化时间
  9. sleep(1)--等待1s
  10. ......

8.2 自定义MySQL函数(一般不用)

  1. --定义函数
  2. delimiter $$
  3. create function f1(
  4.     i1 int,
  5.     i1 int)
  6. returns int
  7. begin
  8.     declare num int;
  9.     declare maxID int;   
  10.     select max(id) from tb1 into maxID;
  11.     set num = i1 + i2 +maxID;
  12.     return(num);
  13. end $$
  14. delimiter;
  15. --调用函数
  16. select f1(11,22);
  17. select f1(11,id),name from tb1;
  18. --删除函数
  19. drop function f1;

8.3 存储过程(不常用)

将一系列SQL语句集合存储在数据库中,当主动去调用存储过程时,其中内部的SQL语句会按照逻辑执行。

相比与使用python执行SQL,可以节约数据传输的时间,但是修改存储过程比较麻烦。

(更新中......)

附1:MySQL时区设置

时区

set time_zone='+0:00':设置时区为0区
show variables like '%time_zone%':查询时区

附2:SQL注入

基于字符串格式化来拼接SQL语句,存在SQL注入风险,如下面代码所示:
例如用户输入user为‘ or 1=1 -- 输入pwd为123,
则下述sql为select * from db1 where name='' or 1=1 -- and password='{}'
--后的被认为是注释,则where条件为1==1就是True,则实际上用户名不需要正确,也不需要密码,也能登录
  1. cursor.execute("use db1")
  2. user = input("请输入用户名")
  3. pwd = input("请输入密码")
  4. sql = "select * from db1 where name='{}' and password='{}'".format(user,pwd)
  5. cursor.excute(sql)
  6. result = cursor.fetchall()
  7. print(result)
为避免SQL注入问题,涉及到用户输入,应避免用传统的字符串格式化,应该用pymysql提供的方法
这种方法会帮助检测输入是否非法,且会帮助转义
  1. cursor.execute("select * from db1 where name=%s and password=%s",[user,pwd])
  2. #或者
  3. cursor.execute("select * from db1 where name=%(n1)s and password=%(n2)s",{"n1":user,"n2":pwd})

附3:sql执行顺序

join
on
where
group by
having
order by
limit
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/397725
推荐阅读
相关标签
  

闽ICP备14008679号