---恢复内容开始---
多表数据: ```python create table dep( id int primary key auto_increment, name varchar(16), work varchar(16) ); create table emp( id int primary key auto_increment, name varchar(16), salary float, dep_id int ); insert into dep values(1, '市场部', '销售'), (2, '教学部', '授课'), (3, '管理部', '开车'); insert into emp(name, salary, dep_id) values('egon', 3.0, 2),('yanghuhu', 2.0, 2),('sanjiang', 10.0, 1),('owen', 88888.0, 2),('liujie', 8.0, 1),('yingjie', 1.2, 0);emp
+----+----------+--------+--------+
| id | name | salary | dep_id |
+----+----------+--------+--------+
| 1 | egon | 3 | 2 |
| 2 | yanghuhu | 2 | 2 |
| 3 | sanjiang | 10 | 1 |
| 4 | owen | 88888 | 2 |
| 5 | liujie | 8 | 1 |
| 6 | yingjie | 1.2 | 0 |
+----+----------+--------+--------+
dep
+----+-----------+--------+
| id | name | work |
+----+-----------+--------+
| 1 | 市场部 | 销售 |
| 2 | 教学部 | 授课 |
| 3 | 管理部 | 开车 |
+----+-----------+--------+
多表连接=>虚拟的单表
内连接
```python
左表 inner join 右表 on 两表有关联的字段的条件
select * from emp inner join dep on emp.dep_id = dep.id;
左连接
左表 left join 右表 on 两表有关联的字段的条件
select * from emp left join dep on emp.dep_id = dep.id;
右连接
左表 right join 右表 on 两表有关联的字段的条件
全连接
select * from emp left join dep on emp.dep_id = dep.id
union
select * from emp right join dep on emp.dep_id = dep.id;
总结,内连接,两表之间存在对应关系的行数才会显示
左连接 左表所有行数都会显示
右连接 右表所有行数都会显示
全连接,将左连接和右连接的结果去重
练习:
查询每一位员工对应的工作职责
select emp.name ,dep.work from emp left join dep on emp.dep_id = dep.id;
2.查询每一个部门下的员工们及员工职责
select max(dep.name) "部门" , group_concat(emp.name) "员工",max(dep.work) "职责" from emp right join dep on emp.dep_id = dep.id group by emp.dep_id;
pymysql模块
#数据库不存在报错,用户和密码不正确报错,port 为数字,其他都是字符串形式
1.建立连接
c = pymysql.connect(host = "localhost",port = 3306,db = "db5",user = "root",password = "123")
2.设置游标
①cursor = c.cursor()#fetchone结果以元组输出,fetchall的结果是元组,元素是每行元素组成的元组
②cursor = c.cursor(pymysql.cursors.DictCursor)#fetchone结果以字典输出,fetchall的结果是列表,元素是每行元素组成的字典
3.书写sql语句,并执行其结果
sql = "slect * from emp"
line = cursor.execute(sql)#返回数据总行数,修改或新增的话返回修改或新增的行数
查询
都无法读出字段信息,没有数据可读时都不会报错
①fetchone一次读一行
②fetchmany(num)指定行数读
③fetchall()全读
4.指针移动:
cursor.scroll(num,mode)
#mode两种(字符串)
①"relative"相对移动
#num>0 向前,num<0 向后
num可移动范围报错
②"absolute"绝对移动
num范围0到line-1,超范围报错
5.提交,不提交的话,无法保存修改和新增的数据
c.commit()
6.断开连接
cursor.close()
c.close()
pymysql sql注入
mysql注释:
/**/
-- 两杠加空格
根本原理:就根据程序的字符串拼接name='%s',我们输入一个xxx' -- haha,用我们输入的xxx加'在程序中拼接成一个判断条件name='xxx' -- haha'
import pymysql
c = pymysql.connect(host ="localhost",port = 3306,db= "db5",user ="root",passwd="123")
cursor = c.cursor(pymysql.cursors.DictCursor)
name = input("input your name>>:").strip()
pwd = input("input your pwd>>:").strip()
sql = "select * from user where name = '%s' and pwd ='%s' "%(name,pwd)
line = cursor.execute(sql)
if line:
print("login successful")
else:
print("login fail")
input your name>>:bob
input your pwd>>:123
login successful
"select * from user where name = '%s' and pwd ='%s' "
原理 name = '%s' %s就是我们输入的数据
-- 后面会认为是空格 需要 再加分号
select * from user where usr="aaa" or 1=1 -- hehe" and pwd="000";
知道用户名时
bob';-- ' 两个分号是匹配最外侧两个分号,也就是%s外面的两个分号用
input your name>>:bob';-- '
input your pwd>>:fafadsfdsa
login successful
当不知道用户名时
dsafa' or 1=1; -- '
input your name>>:dsafa' or 1=1; -- '
input your pwd>>:fdafsa
login successful
解决方案
# 原来是我们对sql进行字符串拼接
# sql="select * from userinfo where name='%s' and password='%s'" %(user,pwd)
# res=cursor.execute(sql)
#改写为(execute帮我们做字符串拼接,我们无需且一定不能再为%s加引号了)
sql="select * from userinfo where name=%s and password=%s" #!!!注意%s需要去掉引号,因为pymysql会自动为我们加上
res=cursor.execute(sql,[user,pwd]) #pymysql模块自动帮我们解决sql注入的问题,只要我们按照pymysql的规矩来。
---恢复内容结束---