昨日内容回顾

  1. 外键的变种三种关系:
  2. 多对一:
  3. 左表的多 对右表一 成立
  4. 左边的一 对右表多 不成立
  5. foreign key(从表的id) refreences 主表的(id
  6. 多对多
  7. 建立第三张表(foreign key
  8. 一对一
  9. foreign key+unique
  10. 单表查询:
  11. 1
  12. where
  13. group by: 分组,通过某个字段 select age,count(1) from user group by age having avg(age)>25;
  14. having
  15. order by
  16. limit 1,2
  17. 多表查询:
  18. 内连接:select * from t1 inner join t2 ; 笛卡尔积
  19. select * from t1 inner join t2 on t2.tid = t1.id;
  20. 左连接:select * from t1 left join t2 on t2.tid = t1.id;
  21. 右连接
  22. 全连接
  23. #select name from department where id in
  24. (select dep_id from employee where age > 25);
  25. select * from employee inner join department
  26. on employee.dep_id = department.id where age > 25;
  27. 子查询
  28. #查询平均年龄在25岁以上的部门名
  29. select * from department
  30. where id in
  31. (select dep_id from employee group by dep_id having avg(age) > 25);
  32. 查询每个部门最新入职的那位员工
  33. select employee.id,employee.name from employee inner join
  34. (select post,max(hire_date) as new_date from employee group by post) as A
  35. on employee.post=A.post
  36. where employee.hire_date = A.new_date;
  37. 取第一名,limit 0,1
  38. 取第二名,limit 1,1
  39. 取第三名,limit 2,1

一、子查询

子查询是将一个查询语句嵌套在另一个查询语句中。

内层查询语句的查询结果,可以为外层查询语句提供查询条件。

子查询中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等关键字

还可以包含比较运算符:= 、 !=、> 、<等

带 in 关键字的子查询

1. 查询平均年龄在 25 岁以上的部门名

步骤分解:

先找出平均年龄大于 25 岁的的员工部门 id

  1. mysql> select dep_id from employee group by dep_id having avg(age) > 25;
  2. +--------+
  3. | dep_id |
  4. +--------+
  5. | 201 |
  6. | 202 |
  7. +--------+
  8. rows in set (0.00 sec)

根据部门 id,到部门表 department 中查询。就可以找到部门名,需要用到上面的查询结果。

使用 where id in (…) 可以得到多条结果。

  1. select id,name from department
  2. where id in
  3. (select dep_id from employee group by dep_id having avg(age) > 25);
  4. #返回结果:
  5. +------+--------------+
  6. | id | name |
  7. +------+--------------+
  8. | 201 | 人力资源 |
  9. | 202 | 销售 |
  10. +------+--------------+

2. 查看技术部员工姓名

步骤分解:

先到部门表中查询技术部的 id

  1. mysql> select id from department where name='技术';
  2. +------+
  3. | id |
  4. +------+
  5. | 200 |
  6. +------+
  7. row in set (0.00 sec)

根据技术部 id,到员工表查询对应的员工姓名

  1. select name from employee
  2. where dep_id in
  3. (select id from department where name='技术');
  4. #返回结果:
  5. +--------+
  6. | name |
  7. +--------+
  8. | egon |
  9. | nvshen |
  10. +--------+

3. 查看不足 1 人的部门名

步骤分解:

先从员工表中查询所有的部门 id

  1. mysql> select dep_id from employee group by dep_id;
  2. +--------+
  3. | dep_id |
  4. +--------+
  5. | 200 |
  6. | 201 |
  7. | 202 |
  8. | 204 |
  9. +--------+
  10. rows in set (0.00 sec)

使用 where id not in (…) 查询不包含上面的 id,就可以得到没有员工的部门

  1. select name from department
  2. where id not in
  3. (select dep_id from employee group by dep_id);
  4. #返回结果:
  5. +--------+
  6. | name |
  7. +--------+
  8. | 运营 |
  9. +--------+

带比较运算符的子查询

  1. #比较运算符:=、!=、>、>=、<、<=、<>
  2. #查询大于所有人平均年龄的员工名与年龄
  3. mysql> select name,age from employee where age > (select avg(age) from employee);
  4. +---------+------+
  5. | name | age |
  6. +---------+------+
  7. | alex | 48 |
  8. | wupeiqi | 38 |
  9. +---------+------+
  10. #查询大于部门内平均年龄的员工名、年龄
  11. 思路:
  12. 1)先对员工表(employee)中的人员分组(group by),查询出dep_id以及平均年龄。
  13. (2)将查出的结果作为临时表,再对根据临时表的dep_idemployeedep_id作为筛选条件将employee表和临时表进行内连接。
  14. (3)最后再将employee员工的年龄是大于平均年龄的员工名字和年龄筛选。
  15. mysql> select t1.name,t1.age from employee as t1
  16. inner join
  17. (select dep_id,avg(age) as avg_age from employee group by dep_id) as t2
  18. on t1.dep_id = t2.dep_id
  19. where t1.age > t2.avg_age;
  20. #返回结果
  21. +------+------+
  22. | name | age |
  23. +------+------+
  24. | alex | 48 |
  25. +------+------+

带 EXISTS 关键字的子查询

  1. #EXISTS关字键字表示存在。在使用EXISTS关键字时,内层查询语句不返回查询的记录。而是返回一个真假值。True或False
  2. #当返回True时,外层查询语句将进行查询;当返回值为False时,外层查询语句不进行查询
  3. #department表中存在dept_id=203,Ture
  4. mysql> select * from employee where exists (select id from department where id=200);
  5. +----+----------+--------+------+--------+
  6. | id | name | sex | age | dep_id |
  7. +----+----------+--------+------+--------+
  8. | 1 | egon | male | 18 | 200 |
  9. | 2 | alex | female | 48 | 201 |
  10. | 3 | wupeiqi | male | 38 | 201 |
  11. | 4 | yuanhao | female | 28 | 202 |
  12. | 5 | nvshen | male | 18 | 200 |
  13. | 6 | xiaomage | female | 18 | 204 |
  14. +----+----------+--------+------+--------+
  15. #department表中存在dept_id=205,False
  16. mysql> select * from employee where exists (select id from department where id=204);
  17. Empty set (0.00 sec)

小练习:

查询每个部门最新入职的那位员工

  1. #删除已存在的表
  2. mysql> drop table employee;
  3. Query OK, 0 rows affected (0.19 sec)
  4. #创建表
  5. create table employee(
  6. id int not null unique auto_increment,
  7. name varchar(20) not null,
  8. sex enum('male','female') not null default 'male', #大部分是男的
  9. age int(3) unsigned not null default 28,
  10. hire_date date not null,
  11. post varchar(50),
  12. post_comment varchar(100),
  13. salary double(15,2),
  14. office int, #一个部门一个房间
  15. depart_id int
  16. );
  17. #查看表结构
  18. mysql> desc employee;
  19. +--------------+-----------------------+------+-----+---------+----------------+
  20. | Field | Type | Null | Key | Default | Extra |
  21. +--------------+-----------------------+------+-----+---------+----------------+
  22. | id | int(11) | NO | PRI | NULL | auto_increment |
  23. | name | varchar(20) | NO | | NULL | |
  24. | sex | enum('male','female') | NO | | male | |
  25. | age | int(3) unsigned | NO | | 28 | |
  26. | hire_date | date | NO | | NULL | |
  27. | post | varchar(50) | YES | | NULL | |
  28. | post_comment | varchar(100) | YES | | NULL | |
  29. | salary | double(15,2) | YES | | NULL | |
  30. | office | int(11) | YES | | NULL | |
  31. | depart_id | int(11) | YES | | NULL | |
  32. +--------------+-----------------------+------+-----+---------+----------------+
  33. #插入记录
  34. #三个部门:教学,销售,运营
  35. insert into employee(name,sex,age,hire_date,post,salary,office,depart_id) values
  36. ('egon','male',18,'20170301','老男孩驻沙河办事处外交大使',7300.33,401,1), #以下是教学部
  37. ('alex','male',78,'20150302','teacher',1000000.31,401,1),
  38. ('wupeiqi','male',81,'20130305','teacher',8300,401,1),
  39. ('yuanhao','male',73,'20140701','teacher',3500,401,1),
  40. ('liwenzhou','male',28,'20121101','teacher',2100,401,1),
  41. ('jingliyang','female',18,'20110211','teacher',9000,401,1),
  42. ('jinxin','male',18,'19000301','teacher',30000,401,1),
  43. ('成龙','male',48,'20101111','teacher',10000,401,1),
  44. ('歪歪','female',48,'20150311','sale',3000.13,402,2),#以下是销售部门
  45. ('丫丫','female',38,'20101101','sale',2000.35,402,2),
  46. ('丁丁','female',18,'20110312','sale',1000.37,402,2),
  47. ('星星','female',18,'20160513','sale',3000.29,402,2),
  48. ('格格','female',28,'20170127','sale',4000.33,402,2),
  49. ('张野','male',28,'20160311','operation',10000.13,403,3), #以下是运营部门
  50. ('程咬金','male',18,'19970312','operation',20000,403,3),
  51. ('程咬银','female',18,'20130311','operation',19000,403,3),
  52. ('程咬铜','male',18,'20150411','operation',18000,403,3),
  53. ('程咬铁','female',18,'20140512','operation',17000,403,3)
  54. ;

小练习题答案

  1. #最新入职,使用max(hire_date) 就可以获取。
  2. #先查询每个部门最新入职的部门名和日期
  3. mysql> select post,max(hire_date) as new_date from employee group by post;
  4. +-----------------------------------------+------------+
  5. | post | new_date |
  6. +-----------------------------------------+------------+
  7. | operation | 2016-03-11 |
  8. | sale | 2017-01-27 |
  9. | teacher | 2015-03-02 |
  10. | 老男孩驻沙河办事处外交大使 | 2017-03-01 |
  11. +-----------------------------------------+------------+
  12. rows in set (0.00 sec)
  13. #根据上一个结果,使用子查询得到员工姓名
  14. select t1.post,t1.name,t1.hire_date from employee as t1
  15. inner join
  16. (select post,max(hire_date) as new_date from employee group by post) as t2
  17. on t1.post=t2.post;
  18. #返回结果
  19. +-----------------------------------------+------------+------------+
  20. | post | name | hire_date |
  21. +-----------------------------------------+------------+------------+
  22. | 老男孩驻沙河办事处外交大使 | egon | 2017-03-01 |
  23. | teacher | alex | 2015-03-02 |
  24. | teacher | wupeiqi | 2013-03-05 |
  25. | teacher | yuanhao | 2014-07-01 |
  26. | teacher | liwenzhou | 2012-11-01 |
  27. | teacher | jingliyang | 2011-02-11 |
  28. | teacher | jinxin | 1900-03-01 |
  29. | teacher | 成龙 | 2010-11-11 |
  30. | sale | 歪歪 | 2015-03-11 |
  31. | sale | 丫丫 | 2010-11-01 |
  32. | sale | 丁丁 | 2011-03-12 |
  33. | sale | 星星 | 2016-05-13 |
  34. | sale | 格格 | 2017-01-27 |
  35. | operation | 张野 | 2016-03-11 |
  36. | operation | 程咬金 | 1997-03-12 |
  37. | operation | 程咬银 | 2013-03-11 |
  38. | operation | 程咬铜 | 2015-04-11 |
  39. | operation | 程咬铁 | 2014-05-12 |
  40. +-----------------------------------------+------------+------------+
  41. #最后取出2个临时表中,最新入职日期相等的结果
  42. select t1.post,t1.name,t1.hire_date from employee as t1
  43. inner join
  44. (select post,max(hire_date) as new_date from employee group by post) as t2
  45. on t1.post=t2.post
  46. where t1.hire_date=t2.new_date;
  47. #返回结果
  48. +-----------------------------------------+--------+------------+
  49. | post | name | hire_date |
  50. +-----------------------------------------+--------+------------+
  51. | 老男孩驻沙河办事处外交大使 | egon | 2017-03-01 |
  52. | teacher | alex | 2015-03-02 |
  53. | sale | 格格 | 2017-01-27 |
  54. | operation | 张野 | 2016-03-11 |
  55. +-----------------------------------------+--------+------------+
  56. rows in set (0.00 sec)

二、MySQl 创建用户和授权

权限管理

我们知道我们的最高权限管理者是 root 用户,它拥有着最高的权限操作。包括select、update、delete、update、grant 等操作。那么一般情况在公司之后 DBA 工程师会创建一个用户和密码,让你去连接数据库的操作,并给当前的用户设置某个操作的权限(或者所有权限)。那么这时就需要我们来简单了解一下:

  • 如何创建用户和密码
  • 给当前的用户授权
  • 移除当前用户的权限

如果你想创建一个新的用户,则需要以下操作:

1.必须使用 root 进入到 mysql 数据库下

  1. mysql -u root
  2. mysql> use mysql
  3. Database changed

2.对新用户增删改

(1). 创建用户

  1. 1.创建用户:
  2. # 指定ip:192.118.1.1的mjj用户登录
  3. create user 'mjj'@'192.118.1.1' identified by '123';
  4. # 指定ip:192.118.1.开头的mjj用户登录
  5. create user 'mjj'@'192.118.1.%' identified by '123';
  6. # 指定任何ip的mjj用户登录
  7. create user 'mjj'@'%' identified by '123';

(2). 删除用户

  1. #语法:
  2. drop user '用户名'@'IP地址';
  3. #举例:删除192.118.1.1的mjj用户登录
  4. mysql> drop user 'mjj'@'192.118.1.1';
  5. Query OK, 0 rows affected (0.00 sec)

注意:删除用户不能直接对 mysql.user 表直接进行操作。

  1. delete from mysql.user where User='mjj';

必须使用 drop user 删除才行。

(3). 修改用户

  1. #格式:
  2. rename user '用户名'@'IP地址' to '新用户名'@'IP地址';
  3. #举例:修改192.118.1.开头的mjj用户的信息
  4. mysql> rename user 'mjj'@'192.118.1.%' to 'msc'@'192.168.10.%';
  5. Query OK, 0 rows affected (0.00 sec)

(4). 修改密码

  1. #格式:
  2. SET PASSWORD FOR '用户名'@'IP地址' = PASSWORD('新密码');
  3. #举例:修改msc的密码
  4. mysql> SET PASSWORD FOR 'msc'@'192.168.10.%' = PASSWORD('123');
  5. Query OK, 0 rows affected, 1 warning (0.00 sec)

3.对当前的用户授权管理

(1). 查看权限

  1. #语法:
  2. show grants for '用户'@'IP地址'
  3. #举例:查询msc用户
  4. mysql> show grants for 'msc'@'192.168.10.%';
  5. +--------------------------------------------+
  6. | Grants for msc@192.168.10.% |
  7. +--------------------------------------------+
  8. | GRANT USAGE ON *.* TO 'msc'@'192.168.10.%' |
  9. +--------------------------------------------+
  10. row in set (0.00 sec)

(2). 授权

  1. #语法:
  2. 1.授权指定权限
  3. grant 权限1,权限2,权限3 on 数据库名.表名 to "用户"@'IP地址';
  4. #举例:给msc用户授权查询,插入,更新 权限。
  5. mysql> grant select ,insert,update on db1.employee to "msc"@'192.168.10.%';
  6. Query OK, 0 rows affected (0.00 sec)
  7. 2.授权所有权限
  8. grant all privileges on 数据库名.表名 to "用户"@'IP地址';
  9. #举例:给msc用户所有权限
  10. mysql> grant all privileges on db1.employee to "msc"@'192.168.10.%';
  11. Query OK, 0 rows affected (0.00 sec)

注意:不能对同一个用户,多次授权不同的权限。否则会有多条授权规则,最终以最严格的权限为准。

(3). 取消权限

  1. #语法:
  2. #取消指定权限
  3. revoke 权限1 on 数据库名.表名 from "用户"@'IP地址';
  4. #举例:取消msc用户的查询权限
  5. mysql> revoke select on db1.employee from "msc"@'192.168.10.%';
  6. Query OK, 0 rows affected (0.00 sec)
  7. #取消所有权限
  8. revoke all privileges on 数据库名.表名 from "用户"@'IP地址';
  9. #举例:取消msc用户employee表所有权限
  10. mysql> revoke all privileges on db1.employee from "msc"@'192.168.10.%';
  11. Query OK, 0 rows affected (0.00 sec)
  12. #举例:取消msc用户所有数据库所有表的权限
  13. mysql> revoke all privileges on *.* from "msc"@'192.168.10.%';
  14. Query OK, 0 rows affected (0.00 sec)

ps:在公司中,一般情况下是 DBA 工程师来做这些授权工作。给你一个用户名和密码,你来连接就可以了。

4.MySql 备份命令行操作

备份 1:数据表结构+数据

  1. #注意:在是mysql>外面执行
  2. C:\Users\xiao>mysqldump -u root -p db1 > db1.sql
  3. Enter password:
  4. #从上面可以看出,当前执行命令的路径为C:\Users\xiao,进入此目录,就可以看到db1.sql文件了。

备份 2:数据表结构

  1. C:\Users\xiao>mysqldump -u root -p -d db1 > db2.sql
  2. Enter password:
  3. #进入C:\Users\xiao目录,就可以看到文件db2.sql

恢复:导入现有的数据到某个数据库

  1. #进入数据库
  2. C:\Users\xiao>mysql -u root -p
  3. Enter password:
  4. #1.先创建一个新的数据库
  5. mysql> create database db10;
  6. #退出
  7. mysql> exit;
  8. Bye
  9. #2.将已有的数据库文件导入到db10数据库中
  10. C:\Users\xiao>mysqldump -u root -p -d db10 < db1.sql
  11. Enter password:
  12. -- MySQL dump 10.13 Distrib 5.7.22, for Win64 (x86_64)
  13. ...
  14. -- Dump completed on 2018-06-14 17:46:50
  15. 出现completed 就表示导入完成

三、掌握 Navicat 的基本使用

本节重点:

  • 掌握 Navicat 的基本使用

在生产环境中操作MySQL数据库还是推荐使用命令行工具mysql,但在我们自己开发测试时,可以使用可视化工具Navicat,以图形界面的形式操作MySQL数据库

官网下载: https://www.navicat.com/en/products/navicat-for-mysql

百度网盘下载:

链接: https://pan.baidu.com/s/1vQI__mrJhTjGz0fAdY_pUA 密码:frjg

官网的要钱,百度网盘是破解版的,只支持 64 位

32 位系统,请访问链接: https://pan.baidu.com/s/1bpo5mqj

下面主要演示 64 位版本的。

1.安装软件

解压 navicat11.1.12_premium_cs_x64.rar 文件。先执行 navicat111_premium_cs_x64.exe 文件

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图1

后面的步骤,直接下一步,下一步,就可以了。

选择桌面图标,右键属性—>快捷方式—>打开文件位置,就能打开安装路径。

默认的安装路径为 C:\Program Files\PremiumSoft\Navicat Premium

将压缩包里面的 navicat.exe 复制到此路径,选择覆盖!这样就完成了破解。注意不要更新!!!

2.连接 MySQL

双击桌面图标,点击连接—>MySQL

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图2

选项说明:

连接名:名字可以随便写

主机或 IP 地址:如果 mysql 在本机上,直接写 localhost 即可。如果是远程的,请填写 IP 地址。

端口:mysql 默认端口为 3306,如果服务器有更改过,请填写对应的端口号。

用户名:授权的用户

密码:认证密码,由于密码为空,这里就不用填写了。

点击下面的连接测试,测试 ok 之后,点击确定

双击 localhost,就可以看到此用户能访问的数据库

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图3

3.新建数据库

右键—>新建数据库

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图4

输入数据库名,字符集选择 utf-8

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图5

这样数据库就创建好了

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图6

4.新建表

双击 db2,选择新建表

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图7

输入字段名 id—>选择数据类型 int—>选择主键—>勾选自动递增—>勾选无符号

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图8

新增第二个字典 name

点击添加栏位—>输入字段名 name—>选择 varchar—>长度为 20

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图9

最后点击上面的保存按钮,输入表名 t1

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图10

5.插入数据

双击 t1 表,就打开表了

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图11

添加数据张三

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图12

点击下面的 √,一条数据就插入好了

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图13

点击左边的 + ,可以继续添加数据

添加 3 条数据

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图14

6. 新建查询

点击上方的查询

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图15

点击下面的新建查询

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图16

输入 sql 语句,点击运行,结果就出来了!

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图17

注意:

批量加注释:ctrl+?键

批量去注释:ctrl+shift+?键

7. 备份库/表

备份库

选中数据库 db2—>右键转储 SQL 文件—>结构和数据

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图18

先选择保存位置,这里选择的是桌面,点击保存

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图19

提示已经完成了,点击关闭按钮。千万不要点击开始,否则它会重新导出一次!

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图20

桌面就有一个 db2.sql 文件

备份表

选择要备份的表—>右键转储 SQL 文件—>结构和数据

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图21

保存位置为桌面,点击保存

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图22

点击关闭按钮,桌面会有一个 t1.sql 文件

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图23

需要掌握基本的操作,就是上面列举上面那些。

四、pymysql 模块的使用

本节重点:

  • pymysql 的下载和使用
  • execute()之 sql 注入
  • 增、删、改:conn.commit()
  • 查:fetchone、fetchmany、fetchall

1. pymysql 的下载和使用

之前我们都是通过 MySQL 自带的命令行客户端工具 mysql 来操作数据库,那如何在 python 程序中操作数据库呢?这就用到了 pymysql 模块,该模块本质就是一个套接字客户端软件,使用前需要事先安装。

pymysql 模块的下载

  1. pip3 install pymysql

pymysql 的使用

准备基础数据

  1. #创建数据库db2,如果已存在,请忽略
  2. CREATE DATABASE db2 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
  3. #创建用户表
  4. CREATE TABLE `userinfo` (
  5. `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
  6. `username` varchar(20) NOT NULL COMMENT '用户名',
  7. `password` varchar(32) NOT NULL COMMENT '密码',
  8. PRIMARY KEY (`id`)
  9. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';
  10. #插入一条数据
  11. INSERT INTO `db2`.`userinfo` (`id`, `username`, `password`) VALUES ('1', 'qiwei', '123');

实现:使用 Python 实现用户登录,如果用户存在则登录成功(假设该用户已在数据库中)

#导入模块
import pymysql


user = input('请输入用户名:')
pwd = input('请输入密码:')


# 1.连接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='', db='db2', charset='utf8')


# 2.创建游标
cursor = conn.cursor()


# 注意%s需要加引号
sql = "select * from userinfo where username='%s' and password='%s'" % (user, pwd)
print('sql语句:',sql)


# 3.执行sql语句
cursor.execute(sql)


result = cursor.execute(sql)  # 执行sql语句,返回sql查询成功的记录数目
print('返回记录数:',result)


# 关闭连接,游标和连接都要关闭
cursor.close()
conn.close()


if result:
    print('登陆成功')
else:
    print('登录失败')

使用 pycharm 执行 py 文件,效果如下:

先来一个错误的

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图24

再来一个正确的

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图25

查看 connect 源代码

def __init__(self, host=None, user=None, password="",
                 database=None, port=0, unix_socket=None,
                 charset='', sql_mode=None,
                 read_default_file=None, conv=None, use_unicode=None,
                 client_flag=0, cursorclass=Cursor, init_command=None,
                 connect_timeout=10, ssl=None, read_default_group=None,
                 compress=None, named_pipe=None, no_delay=None,
                 autocommit=False, db=None, passwd=None, local_infile=False,
                 max_allowed_packet=16*1024*1024, defer_connect=False,
                 auth_plugin_map={}, read_timeout=None, write_timeout=None,
                 bind_address=None, binary_prefix=False):

有几个参数是必须的 host、port、user、password、db

charset 最好也要加上,否则无法识别中文!

2. execute()之 sql 注入

sql 注入之:用户存在,绕过密码

格式:

存在的用户名' -- 任意字符

或者

存在的用户名’ #任意字符

注意:存在的用户名后面,必须有一个单引号。—后面必须有一个空格

代码依然保持不变,输入一个已存在的用户。

测试#

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图26

测试—

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图27

结果提示登录成功

将 sql 复制到 navicat 软件中执行,发现是有结果的。因为 —空格 表示注释。

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图28

sql 注入之:用户不存在,绕过用户与密码

格式:

任意用户名' or 1=1 -- 任意字符

或者

任意用户名' or 1=1 #任意字符

注意:

1.任意用户名后面必须有一个单引号,

2.必须有 or 关键字

3.必须保证等式成立,可以是 2=2

4.—后面必须有空格

5.关键字 or 和等式之间,必须要有空格

先测试—

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图29

再测试#

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图30

将 sql 复制到 navicat 软件中执行,发现是有结果的

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图31

因为 1=1 等式成立,直接忽略用户名判断,所以返回表中的所有数据

用户表再增加一条数据,再次执行同样的 sql。它就是返回表中的所有数据。

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图32

解决方法:

# 原来是我们对sql进行字符串拼接
# sql="select * from userinfo where name='%s' and password='%s'" %(username,pwd)
# print(sql)
# result=cursor.execute(sql)

#改写为(execute帮我们做字符串拼接,我们无需且一定不能再为%s加引号了)
sql="select * from userinfo where name=%s and password=%s" #!!!注意%s需要去掉引号,因为pymysql会自动为我们加上
result=cursor.execute(sql,[user,pwd]) #pymysql模块自动帮我们解决sql注入的问题,只要我们按照pymysql的规矩来。

查看 execute 源代码

def execute(self, query, args=None):
        """Execute a query


        :param str query: Query to execute.


        :param args: parameters used with query. (optional)
        :type args: tuple, list or dict


        :return: Number of affected rows
        :rtype: int


        If args is a list or tuple, %s can be used as a placeholder in the query.
        If args is a dict, %(name)s can be used as a placeholder in the query.
        """

:type args: tuple, list or dict

看上面这句,类型可以是元组,列表,字典。下面分别演示!

元组

#导入模块
import pymysql


user = input('请输入用户名:')
pwd = input('请输入密码:')


# 1.连接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='', db='db2', charset='utf8')


# 2.创建游标
cursor = conn.cursor()


# 注意%s 表示占位符
sql = "select * from userinfo where username = %s and password = %s"
print('sql语句:',sql)


# 3.执行sql语句,返回sql查询成功的记录数
result = cursor.execute(sql,(user,pwd))
print('返回记录数:',result)


# 关闭连接,游标和连接都要关闭
cursor.close()
conn.close()


#判断结果
if result:
    print('登陆成功')
else:
    print('登录失败')

列表

#导入模块
import pymysql


user = input('请输入用户名:')
pwd = input('请输入密码:')


# 1.连接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='', db='db2', charset='utf8')


# 2.创建游标
cursor = conn.cursor()


# 注意%s 表示占位符
sql = "select * from userinfo where username = %s and password = %s"
print('sql语句:',sql)


# 3.执行sql语句,返回sql查询成功的记录数
result = cursor.execute(sql,[user,pwd])
print('返回记录数:',result)


# 关闭连接,游标和连接都要关闭
cursor.close()
conn.close()


#判断结果
if result:
    print('登陆成功')
else:
    print('登录失败')

字典

#导入模块
import pymysql


user = input('请输入用户名:')
pwd = input('请输入密码:')


# 1.连接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='', db='db2', charset='utf8')


# 2.创建游标
cursor = conn.cursor()


# 注意%(username)s 里面的username是字典的key,必须一一对应才行,否则报错!
sql = "select * from userinfo where username = %(username)s and password = %(password)s"
print('sql语句:',sql)


# 3.执行sql语句,返回sql查询成功的记录数
result = cursor.execute(sql,{'username':user,'password':pwd})
print('返回记录数:',result)


# 关闭连接,游标和连接都要关闭
cursor.close()
conn.close()


#判断结果
if result:
    print('登陆成功')
else:
    print('登录失败')

再次使用 sql 注入方式登录,就会登录失败

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图33

3. 增、删、改:conn.commit()

commit()方法:在数据库里增、删、改的时候,必须要进行提交,否则插入的数据不生效。

增加

插入一条数据

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#导入模块
import pymysql


user = input('请输入用户名:')
pwd = input('请输入密码:')


# 1.连接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='', db='db2', charset='utf8')


# 2.创建游标
cursor = conn.cursor()


sql = "insert into userinfo(username,password) values (%s,%s)"
print('sql语句:',sql)


# 3.执行sql语句,返回sql查询成功的记录数
#插入一条数据
result = cursor.execute(sql,(user,pwd))
print('返回记录数:',result)


#一定记得commit
conn.commit()


# 关闭连接,游标和连接都要关闭
cursor.close()
conn.close()


#判断结果
if result:
    print('ok')
else:
    print('error')

执行效果如下:

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图34

查看表记录

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图35

同时插入多条数据

#导入模块
import pymysql


user = input('请输入用户名:')
pwd = input('请输入密码:')


# 1.连接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='', db='db2', charset='utf8')


# 2.创建游标
cursor = conn.cursor()


sql = "insert into userinfo(username,password) values (%s,%s)"
print('sql语句:',sql)


# 3.执行sql语句,返回sql查询成功的记录数
#同时插入多条数据
result = cursor.executemany(sql,[(user+'1',pwd),(user+'2',pwd)])
print('返回记录数:',result)


#一定记得commit
conn.commit()


# 关闭连接,游标和连接都要关闭
cursor.close()
conn.close()


#判断结果
if result:
    print('ok')
else:
    print('error')

执行效果如下:

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图36

查看表记录

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图37

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#导入模块
import pymysql


user = input('请输入用户名:')
pwd = input('请输入密码:')


# 1.连接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='', db='db2', charset='utf8')


# 2.创建游标
cursor = conn.cursor()


sql = "update userinfo set username = %s  where id = '8'"
print('sql语句:',sql)


# 3.执行sql语句,返回sql查询成功的记录数
#修改一条数据
result = cursor.execute(sql,user)
print('返回记录数:',result)


#一定记得commit
conn.commit()


# 关闭连接,游标和连接都要关闭
cursor.close()
conn.close()


#判断结果
if result:
    print('ok')
else:
    print('error')

执行效果如下:

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图38

查看表记录

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图39

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#导入模块
import pymysql


#删除不需要执行这2个input了
# user = input('请输入用户名:')
# pwd = input('请输入密码:')


# 1.连接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='', db='db2', charset='utf8')


# 2.创建游标
cursor = conn.cursor()


sql = "delete from userinfo  where id = '2'"
print('sql语句:',sql)


# 3.执行sql语句,返回sql查询成功的记录数
#删除一条数据
result = cursor.execute(sql)
print('返回记录数:',result)


#一定记得commit
conn.commit()


# 关闭连接,游标和连接都要关闭
cursor.close()
conn.close()


#判断结果
if result:
    print('ok')
else:
    print('error')

input 不需要执行了,直接注释掉即可

执行效果如下:

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图40

查看表记录

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图41

4. 查:fetchone、fetchmany、fetchall

fetchone():获取下一行数据,第一次为首行;
fetchall():获取所有行数据源
fetchmany(4):获取4行数据

查看一下表内容:

mysql> select * from userinfo;
+----+-----------+----------+
| id | username  | password |
+----+-----------+----------+
|  1 | qiwei     | 123      |
|  6 | 高圆圆    | 123      |
|  7 | 舒畅1     | 123      |
|  8 | 刘思思    | 123      |
+----+-----------+----------+
rows in set (0.00 sec)

使用 fetchone():

#导入模块
import pymysql


# 1.连接
conn = pymysql.connect(host='localhost', port=3306, user='root', password='', db='db2', charset='utf8')


# 2.创建游标
cursor = conn.cursor()


sql = 'select * from userinfo'
cursor.execute(sql)


# 查询第一行的数据
row = cursor.fetchone()
print(row) # (1, 'qiwei', '123')


# 查询第二行数据
row = cursor.fetchone()
print(row) # (6, '高圆圆', '123')


# 4.关闭游标
cursor.close()


# 5.关闭连接
conn.close()

使用 fetchall():

#导入模块
import pymysql


# 1.连接
conn = pymysql.connect(host='localhost', port=3306, user='root', password='', db='db2', charset='utf8')


# 2.创建游标
cursor = conn.cursor()


sql = 'select * from userinfo'
cursor.execute(sql)


# 获取所有的数据
rows = cursor.fetchall()
print(rows)


# 4.关闭游标
cursor.close()


# 5.关闭连接
conn.close()

运行结果如下:

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图42

默认情况下,我们获取到的返回值是元组,只能看到每行的数据,却不知道每一列代表的是什么,这个时候可以使用以下方式来返回字典,每一行的数据都会生成一个字典:

cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)  
#在实例化的时候,将属性cursor设置为pymysql.cursors.DictCursor

再次运行,结果如下:

[{'id': 1, 'username': 'qiwei', 'password': '123'}, {'id': 6, 'username': '高圆圆', 'password': '123'}, {'id': 7, 'username': '舒畅 1', 'password': '123'}, {'id': 8, 'username': '刘思思', 'password': '123'}]

在 fetchone 示例中,在获取行数据的时候,可以理解开始的时候,有一个行指针指着第一行的上方,获取一行,它就向下移动一行,所以当行指针到最后一行的时候,就不能再获取到行的内容,所以我们可以使用如下方法来移动行指针:

cursor.scroll(1,mode='relative')  # 相对当前位置移动
cursor.scroll(2,mode='absolute') # 相对绝对位置移动
第一个值为移动的行数,整数为向下移动,负数为向上移动,mode指定了是相对当前位置移动,还是相对于首行移动

举例:

#导入模块
import pymysql


# 1.连接
conn = pymysql.connect(host='localhost', port=3306, user='root', password='', db='db2', charset='utf8')


# 2.创建游标
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)


sql = 'select * from userinfo'
cursor.execute(sql)


# 查询第一行的数据
row = cursor.fetchone()
print(row) # {'password': '123', 'username': 'qiwei', 'id': 1}


# 查询第二行数据
row = cursor.fetchone()
print(row) # {'username': '高圆圆', 'password': '123', 'id': 6}


cursor.scroll(-1,mode='relative') #设置之后,光标相对于当前位置往前移动了一行,所以打印的结果为第二行的数据
row = cursor.fetchone()
print(row)  # {'id': 6, 'username': '高圆圆', 'password': '123'}


cursor.scroll(0,mode='absolute') #设置之后,光标相对于首行没有任何变化,所以打印的结果为第一行数据
row = cursor.fetchone()
print(row)  # {'id': 1, 'username': 'qiwei', 'password': '123'}


# 4.关闭游标
cursor.close()


# 5.关闭连接
conn.close()

执行结果为:

Day63 子查询,MySQl创建用户和授权,可视化工具Navicat的使用,pymysql模块的使用 - 图43

fetchmany():

#导入模块
import pymysql


# 1.连接
conn = pymysql.connect(host='localhost', port=3306, user='root', password='', db='db2', charset='utf8')


# 2.创建游标
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)


sql = 'select * from userinfo'
cursor.execute(sql)


# 获取2条数据
rows = cursor.fetchmany(2)
print(rows)


# 4.关闭游标
cursor.close()


# 5.关闭连接
conn.close()

执行结果为:

[{'id': 1, 'username': 'qiwei', 'password': '123'}, {'id': 6, 'username': '高圆圆', 'password': '123'}]