目录

mysql语句注释

利用注释备注信息(注释用的6 也可以造成SQL注入

-- 这是行注释,这一行从这里开始的SQL语句都不会被执行

# 这也是行注释,这一行从这里开始的SQL语句都不会被执行

/*
这是块注释,写在里面的SQL语句都不会被执行
*/

navicat 的基本使用

我们使用 navicat 这个数据库图形化界面管理软件来简化数据库操作,提高开发效率

特色(个人总结)

就现阶段用到而言

  • 把许多数据库基本操作语句用 鼠标点点点 的方式完成,并且可以看到操作对应的 sql 语句
  • 语法提示
  • 关键字颜色标识,不容易打错字单词
  • 模型功能(设计、分析数据关系十分便利)
  • 导入导出功能十分强大
  • 支持多种数据库服务器(可以保存连接,点击登录)

navicat 官方使用手册写的还是挺详细的,图文结合,想要详细了解可以戳过去看看

此部分仅作为个人 navicat 使用快速查阅区

有些部分比较简单,就只写了一个标题,表示必须步骤

可以支持很多种数据库,可视化客户端界面

与数据服务器建立连接

创建&打开数据库、表

创建

选中上一级对象右键新建...

数据库连接 > 数据库 > 数据表 > 表记录 (忽略其他对象)

打开

直接双击数据库、表即可(像windows操作文件目录一样)

修改操作表结构

修改表结构

查询修改操作表数据

基本语句对应的操作

忘了这里是打算写什么了,先空着吧...

模型 ***** 特色功能

从数据库建立模型

模型页面基本操作

常用功能个人小结

  • 鼠标放在表上可以到与之关联的表
  • 鼠标放在线上可关联关系(外键)
  • 双击表可以改表结构
  • 右键重命名可以改表名
  • 右下角有历史记录区,可回退
  • 如图标注移动与整理格式视图功能
  • 与库表结构之间的相互转换

用模型设计数据库并导出

打开模型视图

在工作区创建表

创建表字段关联(外键)

将模型导出

可以导出数据库,也可导出表

结构、数据导入导出

导出

注意对象(库、表)

导入

一般导出的sql 文件中都有drop ... if exisists .... ,用之前慎重

附属小功能

刷新小按钮

点击刷新小图标 或者选中对应对象右键刷新

查看操作对应sql语句

很多地方都有这个SQL预览

执行时间查看

可以对自己的 sql 语句性能有个粗略评估

手动筛选数据

练习

习题引自 多表查询练习题

数据准备

create database day38;

create table test(
id int primary key auto_increment,
name varchar(32),
sex enum('male', 'female', 'others') default 'male' not null
); insert into test values(''), ('');

使用SQL语句导入表结构与数据

SET NAMES utf8;
SET FOREIGN_KEY_CHECKS = 0; -- ----------------------------
-- Table structure for `class`
-- ----------------------------
DROP TABLE IF EXISTS `class`;
CREATE TABLE `class` (
`cid` int(11) NOT NULL AUTO_INCREMENT,
`caption` varchar(32) NOT NULL,
PRIMARY KEY (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; -- ----------------------------
-- Records of `class`
-- ----------------------------
BEGIN;
INSERT INTO `class` VALUES ('1', '三年二班'), ('2', '三年三班'), ('3', '一年二班'), ('4', '二年九班');
COMMIT; -- ----------------------------
-- Table structure for `course`
-- ----------------------------
DROP TABLE IF EXISTS `course`;
CREATE TABLE `course` (
`cid` int(11) NOT NULL AUTO_INCREMENT,
`cname` varchar(32) NOT NULL,
`teacher_id` int(11) NOT NULL,
PRIMARY KEY (`cid`),
KEY `fk_course_teacher` (`teacher_id`),
CONSTRAINT `fk_course_teacher` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`tid`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; -- ----------------------------
-- Records of `course`
-- ----------------------------
BEGIN;
INSERT INTO `course` VALUES ('1', '生物', '1'), ('2', '物理', '2'), ('3', '体育', '3'), ('4', '美术', '2');
COMMIT; -- ----------------------------
-- Table structure for `score`
-- ----------------------------
DROP TABLE IF EXISTS `score`;
CREATE TABLE `score` (
`sid` int(11) NOT NULL AUTO_INCREMENT,
`student_id` int(11) NOT NULL,
`course_id` int(11) NOT NULL,
`num` int(11) NOT NULL,
PRIMARY KEY (`sid`),
KEY `fk_score_student` (`student_id`),
KEY `fk_score_course` (`course_id`),
CONSTRAINT `fk_score_course` FOREIGN KEY (`course_id`) REFERENCES `course` (`cid`),
CONSTRAINT `fk_score_student` FOREIGN KEY (`student_id`) REFERENCES `student` (`sid`)
) ENGINE=InnoDB AUTO_INCREMENT=53 DEFAULT CHARSET=utf8; -- ----------------------------
-- Records of `score`
-- ----------------------------
BEGIN;
INSERT INTO `score` VALUES ('1', '1', '1', '10'), ('2', '1', '2', '9'), ('5', '1', '4', '66'), ('6', '2', '1', '8'), ('8', '2', '3', '68'), ('9', '2', '4', '99'), ('10', '3', '1', '77'), ('11', '3', '2', '66'), ('12', '3', '3', '87'), ('13', '3', '4', '99'), ('14', '4', '1', '79'), ('15', '4', '2', '11'), ('16', '4', '3', '67'), ('17', '4', '4', '100'), ('18', '5', '1', '79'), ('19', '5', '2', '11'), ('20', '5', '3', '67'), ('21', '5', '4', '100'), ('22', '6', '1', '9'), ('23', '6', '2', '100'), ('24', '6', '3', '67'), ('25', '6', '4', '100'), ('26', '7', '1', '9'), ('27', '7', '2', '100'), ('28', '7', '3', '67'), ('29', '7', '4', '88'), ('30', '8', '1', '9'), ('31', '8', '2', '100'), ('32', '8', '3', '67'), ('33', '8', '4', '88'), ('34', '9', '1', '91'), ('35', '9', '2', '88'), ('36', '9', '3', '67'), ('37', '9', '4', '22'), ('38', '10', '1', '90'), ('39', '10', '2', '77'), ('40', '10', '3', '43'), ('41', '10', '4', '87'), ('42', '11', '1', '90'), ('43', '11', '2', '77'), ('44', '11', '3', '43'), ('45', '11', '4', '87'), ('46', '12', '1', '90'), ('47', '12', '2', '77'), ('48', '12', '3', '43'), ('49', '12', '4', '87'), ('52', '13', '3', '87');
COMMIT; -- ----------------------------
-- Table structure for `student`
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`sid` int(11) NOT NULL AUTO_INCREMENT,
`gender` char(1) NOT NULL,
`class_id` int(11) NOT NULL,
`sname` varchar(32) NOT NULL,
PRIMARY KEY (`sid`),
KEY `fk_class` (`class_id`),
CONSTRAINT `fk_class` FOREIGN KEY (`class_id`) REFERENCES `class` (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8; -- ----------------------------
-- Records of `student`
-- ----------------------------
BEGIN;
INSERT INTO `student` VALUES ('1', '男', '1', '理解'), ('2', '女', '1', '钢蛋'), ('3', '男', '1', '张三'), ('4', '男', '1', '张一'), ('5', '女', '1', '张二'), ('6', '男', '1', '张四'), ('7', '女', '2', '铁锤'), ('8', '男', '2', '李三'), ('9', '男', '2', '李一'), ('10', '女', '2', '李二'), ('11', '男', '2', '李四'), ('12', '女', '3', '如花'), ('13', '男', '3', '刘三'), ('14', '男', '3', '刘一'), ('15', '女', '3', '刘二'), ('16', '男', '3', '刘四');
COMMIT; -- ----------------------------
-- Table structure for `teacher`
-- ----------------------------
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher` (
`tid` int(11) NOT NULL AUTO_INCREMENT,
`tname` varchar(32) NOT NULL,
PRIMARY KEY (`tid`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; -- ----------------------------
-- Records of `teacher`
-- ----------------------------
BEGIN;
INSERT INTO `teacher` VALUES ('1', '张磊老师'), ('2', '李平老师'), ('3', '刘海燕老师'), ('4', '朱云海老师'), ('5', '李杰老师');
COMMIT; SET FOREIGN_KEY_CHECKS = 1;

如何验证答案是否正确

语句写出来不一定是对的,此时需要举一两个例子去验证

题目

选几道做做掌握方法即可

# 1、查询所有的课程的名称以及对应的任课老师姓名

# 2、查询学生表中男女生各有多少人

# 3、查询物理成绩等于100的学生的姓名

# 4、查询平均成绩大于八十分的同学的姓名和平均成绩

# 5、查询所有学生的学号,姓名,选课数,总成绩

# 6、 查询姓李老师的个数

# 7、 查询没有报李平老师课的学生姓名

# 8、 查询物理课程比生物课程高的学生的学号

# 9、 查询没有同时选修物理课程和体育课程的学生姓名

# 10、查询挂科超过两门(包括两门)的学生姓名和班级、查询选修了所有课程的学生姓名

# 12、查询李平老师教的课程的所有成绩记录

# 13、查询全部学生都选修了的课程号和课程名

# 14、查询每门课程被选修的次数

# 15、查询之选修了一门课程的学生姓名和学号

# 16、查询所有学生考出的成绩并按从高到低排序(成绩去重)

# 17、查询平均成绩大于85的学生姓名和平均成绩

# 18、查询生物成绩不及格的学生姓名和对应生物分数

# 19、查询在所有选修了李平老师课程的学生中,这些课程(李平老师的课程,不是所有课程)平均成绩最高的学生姓名

# 20、查询每门课程成绩最好的前两名学生姓名

# 21、查询不同课程但成绩相同的学号,课程号,成绩

# 22、查询没学过“叶平”老师课程的学生姓名以及选修的课程名称;

# 23、查询所有选修了学号为1的同学选修过的一门或者多门课程的同学学号和姓名;

# 24、任课最多的老师中学生单科成绩最高的学生姓名

部分参考答案(只放了两题的)

# 1、查询所有的课程的名称以及对应的任课老师姓名
SELECT course.cname, teacher.tname FROM course INNER JOIN teacher ON course.teacher_id=teacher.tid; # 2、查询学生表中男女生各有多少人 # 利用group分组与聚合函数 count计数
-- SELECT * FROM student;
SELECT gender, COUNT(sid) FROM student GROUP BY gender; # 3、查询物理成绩等于100的学生的姓名 # 4、查询平均成绩大于八十分的同学的姓名和平均成绩 # 5、查询所有学生的学号,姓名,选课数,总成绩 # 6、 查询姓李老师的个数 # 7、 查询没有报李平老师课的学生姓名 # 8、 查询物理课程比生物课程高的学生的学号 # 9、 查询没有同时选修物理课程和体育课程的学生姓名 # 10、查询挂科超过两门(包括两门)的学生姓名和班级、查询选修了所有课程的学生姓名 # 12、查询李平老师教的课程的所有成绩记录 # 13、查询全部学生都选修了的课程号和课程名 # 14、查询每门课程被选修的次数 # 15、查询之选修了一门课程的学生姓名和学号 # 16、查询所有学生考出的成绩并按从高到低排序(成绩去重) # 17、查询平均成绩大于85的学生姓名和平均成绩 # 18、查询生物成绩不及格的学生姓名和对应生物分数 # 19、查询在所有选修了李平老师课程的学生中,这些课程(李平老师的课程,不是所有课程)平均成绩最高的学生姓名 # 20、查询每门课程成绩最好的前两名学生姓名 # 21、查询不同课程但成绩相同的学号,课程号,成绩 # 22、查询没学过“叶平”老师课程的学生姓名以及选修的课程名称; # 23、查询所有选修了学号为1的同学选修过的一门或者多门课程的同学学号和姓名; # 24、任课最多的老师中学生单科成绩最高的学生姓名

少数题推导歩鄹(记录思路)

-- 1、查询所有的课程的名称以及对应的任课老师姓名
# 所有课程信息
-- SELECT * FROM course;
# 老师表的信息
-- SELECT * FROM teacher;
# 两张表是一一对应的关系,直接根据 老师id 用内连接连起来即可
# 与老师信息对应起来
SELECT course.cname, teacher.tname FROM course INNER JOIN teacher ON course.teacher_id=teacher.tid; # 3、查询物理成绩等于100的学生的姓名
# 审题: 涉及到模型中的 课程表、成绩表、学生表
# 先看看课程表
SELECT * FROM course; # 有 cid 跟成绩表关联
# 看看成绩表
SELECT * FROM score; # 有学生 id 和 分数
# 看看学生表
SELECT * FROM student; # 有学生名还有 学生 id # 先查出课程表中物理课的 cid
SELECT course.cid FROM course WHERE cname='物理';
# 将上一步的查询结果cid 与成绩表 course_id关联
SELECT * FROM score WHERE score.course_id=(SELECT course.cid FROM course WHERE cname='物理');
# 物理成绩等于100 分的学生 sid ---> sid 和 student_id 引起歧义了。。。。 千万不要搞错了
SELECT score.student_id FROM score WHERE num = 100 and score.course_id=(SELECT course.cid FROM course WHERE cname='物理');
# 用上一步的结果 sid 与学生表 sid 关联,查出学生姓名
SELECT * FROM student WHERE student.sid in (SELECT score.student_id FROM score WHERE num = 100 and score.course_id=(SELECT course.cid FROM course WHERE cname='物理')); -- 4、查询平均成绩大于八十分的同学的姓名和平均成绩
-- 先查平均成绩大于80分的
-- 有错
-- SELECT student.sname, tmp.avg_num FROM student
-- LEFT JOIN
-- (SELECT score.student_id, AVG(score.num) as avg_num FROM score GROUP BY score.student_id HAVING AVG(score.num) > 80) AS tmp
-- ON
-- student.sid=tmp.student_id; -- 7、 查询没有报李平老师课的学生姓名
-- SELECT * FROM teacher LEFT JOIN course ON teacher.tid=course.teacher_id and teacher.tname='李平老师'; -- SELECT teacher.tid FROM teacher WHERE teacher.tname='李平老师';
-- SELECT * FROM course WHERE course.teacher_id=(SELECT teacher.tid FROM teacher WHERE teacher.tname='李平老师')
-- SELECT course.cid FROM course WHERE course.teacher_id=(SELECT teacher.tid FROM teacher WHERE teacher.tname='李平老师') -- 8、 查询没有同时选修物理课程和体育课程的学生姓名(规定必须选了)
-- SELECT course.cid FROM course WHERE course.cname='物理' or course.cname='体育'; # 2, 3
-- SELECT * FROM score WHERE score.course_id IN (
-- SELECT course.cid FROM course WHERE course.cname='物理' or course.cname='体育'
-- );
# 只有一门的学生
-- SELECT score.student_id FROM score WHERE score.course_id IN (
-- SELECT course.cid FROM course WHERE course.cname='物理' or course.cname='体育'
-- ) GROUP BY score.student_id HAVING COUNT(score.student_id)=1;
-- SELECT student.sname FROM student WHERE student.sid IN (
-- SELECT score.student_id FROM score WHERE score.course_id IN (
-- SELECT course.cid FROM course WHERE course.cname='物理' or course.cname='体育'
-- ) GROUP BY score.student_id HAVING COUNT(score.student_id)=1
-- );
-- # 可以把 course.cname='物理' or course.cname='体育' 改成 in ('体育', '物理') -- 9、 查询挂科超过两门(包括两门)的学生姓名和班级
-- SELECT * FROM score WHERE score.num < 60;
-- SELECT score.student_id FROM score WHERE score.num < 60
-- GROUP BY score.student_id
-- HAVING COUNT(score.student_id) >= 2
-- ;
-- SELECT * FROM student WHERE student.sid IN (
-- SELECT score.student_id FROM score WHERE score.num < 60
-- GROUP BY score.student_id
-- HAVING COUNT(score.student_id) >= 2)
-- ;
SELECT class.caption, student.sname FROM student
INNER JOIN class ON class.cid=student.class_id
WHERE student.sid IN (
SELECT score.student_id FROM score WHERE score.num < 60
GROUP BY score.student_id
HAVING COUNT(score.student_id) >= 2)
;

亦可处理好缩进 选择部分代码执行 推导每步执行结果

select student.sname from student where sid not  in(
select distinct student_id from score where course_id in(
select course.cid from course inner join teacher on course.teacher_id = teacher.tid where tid = (
select tid from teacher where tname = '李平老师'
)
)
)
;

核心点--解题思路与注意点、小结

个人解题思路与技巧

  • 一定要分步一点点写,写一点查一点

    ​ 虽然慢,但也比写不出来强不要太多呀!

  • 一定要保留上一步的代码,方便回看或者保持好缩进,可以每次选择前几步的结果来查询

    ​ 后面写不下去了,或者哪里突然写错了,方便排查错误

  • 根据哪张表字段关联什么,可以得到什么 来当成查询返回目标字段(select 后面)

    ​ 每一步查出来的结果都是下一步所需的字段,score表有学生id 是我查老师所教学生的所要的条件

    select score.student_id from score where score.course_id in (
    select course.id from course where course.teacher_id in (
    select teacher.id from teacher where teacher.name in ('李平老师', 'tank老师')
    )
    )
    )
    ; # 采用这样的缩进可以选中不同部分去执行,可以看到查询结果(分号在最后一行,只管套就行了)
  • 表的字段都用表名来点(teacher.tid student.name 这样) 后续歩鄹多了很可能会和其他表有冲突,在找问题时也不够清晰,你还要去分析这个id是哪里的id

    ​ 带上表名一眼就知道了

  • 分号直接放在最后一行

    ​ 嵌套逐步推导式不用关心引号了,不然还删了,再在最外层加

小结

  • 两个表合起来一定是 inner join(left join 或者 right join这些一般用不到)

  • 子查询一般拿来做条件且只返回一个字段, id in (select student.id ...)

  • 数据从虚拟表里拿 --> 外层表拿里层表(括号里执行产生虚拟表)里的数据

    ​ 从括号里查询结果中拿取数据

某题详细分析思路(没有写完)

题目

查询物理成绩等于100的学生的姓名

分析流程、技巧/注意点

用面向过程的思路来分步解决

看题分析用到哪些表

查询物理成绩等于100的学生的姓名

涉及到 课程表、成绩表、学生表

在模型中查看表关联

可以开着navicat的模型关系图,筛选出与题目相关联的表,拉出来,看清楚各个表之间的关联字段,要得到什么字段需要经过哪些表,如何得出。

查看表结构与内容,标注每一步的关联字段

看看课程表 SELECT * FROM course; # 有 cid 跟成绩表关联

# 看看成绩表 SELECT * FROM score; # 有学生 sid 和 分数

# 看看学生表 SELECT * FROM student; # 有学生名还有 学生 id

分步去推导出结果

找一个起点,一点一点的查出想要的数据

.... 后续空闲了再来补充

人工分析验证语句执行结果是否正确

其实校验每一步执行的结果递推也可以确定答案是否正确

从最开始的语句一句一句往下面执行推导结果

分块语句一小块一小块往外面执行

推荐还是从最初那步开始去校对结果

一步一步复杂的去验证,全部都没问题,那就没问题(或者考虑没有的情况,选课,没选课的呢?)

题目:查询物理成绩等于100的学生的姓名

按思路人工查表

如果记录不存在,可能此人工查法结果是错的,如果中间有联表,可能也是错的 --> 应该是没问题的,后面验证下(最近太忙了, emmm)

查出课程表中物理课的 cid

根据上一步查出的 cid 去成绩表查满足条件的 student_id

筛选分数

根据上一步获取到的 student_id 去student表查 sname ---> 即最终结果

将最终结果与语句执行结果相比较

如果有误,校对SQL语句或人工查询是否有误

通过 python 进行 MySQL 操作

先安装 pymysql 模块

打开设置

打开搜索页面

搜索并安装pymysql模块

安装完毕即可

参考数据

teacher表

查询案例

点进去看源码及参数,返回值,可以知道他的用法以及参数,返回值,其他功能

读数据时注意游标的移动,类似于文件的读取等操作

普通查询操作

前提:要事先创建好数据库

conn连接对象.cursor() cursor游标对象.execute() cursor游标对象.fetchone() cursor游标对象.fetchmany() cursor游标对象.fetchall() cursor游标对象.scroll() cursor游标对象.close() conn连接对象.close()

import pymysql

conn = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
password='000000',
database='day38',
charset='utf8' # 编码千万不要加 - --> utf-8 会直接报错
) # cursor = conn.cursor() # 产生一个游标对象(闪烁的输入 _)
# sql = 'select * from teacher'
# res = cursor.execute(sql) # 执行传入的sql 语句
# # 5
# print(res) # res其实是执行语句返回的数据条数
# print(cursor.fetchone())
# # (1, '张磊老师')
# print(cursor.fetchall()) # 下面从第二条开始了。。。 取了就没了(队列,文件光标移动)
# # ((2, '李平老师'), (3, '刘海燕老师'), (4, '朱云海老师'), (5, '李杰老师'))
# print(cursor.fetchmany())
# # () # ---------------------------------------------------
# conn.cursor() 产生一个游标对象
# 不写参数 默认将每条数据以元组返回
# pymysql.cursors.DictCursor 以字典的形式返回每条记录
# ---------------------------------------------------
cursor = conn.cursor(pymysql.cursors.DictCursor) # 产生一个游标对象(闪烁的输入 _) 以字典的形式返回查询出来的数据, 键是表的字段,值是...
sql = 'select * from teacher' # ---------------------------------------------------
# cursor.execute() 拼接执行sql语句
# ---------------------------------------------------
res = cursor.execute(sql) # 执行传入的sql 语句
# 5
print(res) # res其实是执行语句返回的数据条数 # ---------------------------------------------------
# cursor.fetchone() 从当前游标位置开始查询一个记录
# 游标会自动后移一位
# ---------------------------------------------------
print(cursor.fetchone())
# {'tid': 1, 'tname': '张磊老师'} # ---------------------------------------------------
# cursor.fetchmany() 从当前游标位置开始往后读取n条数据
# 游标会自动后移n行
# ---------------------------------------------------
print(cursor.fetchmany(2))
# [{'tid': 2, 'tname': '李平老师'}, {'tid': 3, 'tname': '刘海燕老师'}] # ---------------------------------------------------
# cursor.fetchall() 从当前游标位置开始读取全部数据
# 游标会自动后移至末尾
# ---------------------------------------------------
print(cursor.fetchall()) # 下面从第二条开始了。。。 取了就没了(队列,文件光标移动)
# [{'tid': 4, 'tname': '朱云海老师'}, {'tid': 5, 'tname': '李杰老师'}] # ---------------------------------------------------
# cursor.scroll() 移动游标
# absolute 直接移到第n 行
# relative 根据当前位置将游标往后移动n 行
# ---------------------------------------------------
cursor.scroll(0, 'absolute') # 数字 absolute 相对于起始位置往后移动几位
print(cursor.fetchall())
# [{'tid': 1, 'tname': '张磊老师'}, {'tid': 2, 'tname': '李平老师'}, {'tid': 3, 'tname': '刘海燕老师'}, {'tid': 4, 'tname': '朱云海老师'}, {'tid': 5, 'tname': '李杰老师'}] cursor.scroll(0, 'absolute') # 移至最开头
cursor.scroll(1, 'relative') # 数字 relative 相对当前位置往后移动几位
print(cursor.fetchall())
# [{'tid': 2, 'tname': '李平老师'}, {'tid': 3, 'tname': '刘海燕老师'}, {'tid': 4, 'tname': '朱云海老师'}, {'tid': 5, 'tname': '李杰老师'}] # ---------------------------------------------------
# cursor.close() 关闭游标
# ---------------------------------------------------
cursor.close()
# ---------------------------------------------------
# conn.close() 关闭连接
# ---------------------------------------------------
conn.close()

前置数据

CREATE TABLE `user`  (
`id` int(11) PRIMARY KEY AUTO_INCREMENT,
`name` varchar(255),
`password` varchar(255)
) ; insert into user (name, password) values ('jason', '123'), ('tank', '123'), ('jerry', '123');

SQL注入

SQL注入:利用注释等具有特殊意义的符号,来完成一些骚操作

# 利用字符串拼接的特点, 传入了注释,把密码校验屏蔽掉了
# 即知道用户名就能登录了
select * from user where name = 'jason' -- safgwe and password = 'sanadawgw'; # 利用字符串拼接的特点,跳过用户名与密码校验
select * from user where name = 'sagas' or 1 = 1 -- and password = '123';

select * from user where name = 'jason' -- safgwe and password = 'sanadawgw';

select * from user where name = 'sagas' or 1 = 1 -- and password = '123';

在python中可以print 一下自己的sql 语句,拿出来执行一下或者放在 navicat 中(有颜色的区别)即可看出端倪

避免SQL注入

后续写sql 语句,不要手动拼接关键性的数据,而是用 execute 帮你去拼接

方法的使用可以养成习惯,点进去看看,参数返回值都有,而且还会有简单的英文注释

cursor游标对象.mogrify() cursor游标对象.execute()

import pymysql

conn = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
password='000000',
database='day38',
charset='utf8' # 编码千万不要加 - --> utf-8 会直接报错
) cursor = conn.cursor() username = input("username>>>: ").strip()
password = input("password>>>: ").strip()
# SQL 注入
# sql = f"select * from user where name = '{username}' and password = '{password}'"
# print(sql)
# res = cursor.execute(sql)
# if res:
# print(cursor.fetchall())
# else:
# print("用户名或密码错误")
# # username>>>: jason
# # password>>>: 123
# # select * from user where name = 'jason' and password = '123'
# # ((1, 'jason', '123'),) # # username>>>: jason' -- sadagas
# # password>>>:
# # 也可以进去
#
# # username>>>: xxx' or 1=1 --sasgsafg
# # password>>>:
# # 也可以进去 # 解决版
sql = "select * from user where name = %s and password = %s"
# print(sql) # ---------------------------------------------------
# cursor.mogrify() 拼接sql语句
# 可以在 execute前将语句打印出来,便于排错
# ---------------------------------------------------
print("通过 cursor.mogrify 查看 execute 要执行的语句(execute的中间步骤):" + cursor.mogrify(sql, [username, password])) # execute 可以自动解决 Bug, 自动识别并拼接语句中的 %s
# ---------------------------------------------------
# cursor.execute() 执行SQL语句,可拼接防注入
# 传入sql语句自动执行,也可识别 %s 用后面参数替换
# ---------------------------------------------------
res = cursor.execute(sql, [username, password]) if res:
print(cursor.fetchone())
else:
print("用户名或密码错误")
# username>>>: tanksadas
# password>>>: sagas
# 通过 cursor.mogrify 查看 execute 要执行的语句(execute的中间步骤):select * from user where name = 'tanksadas' and password = 'sagas'
# 用户名或密码错误 cursor.close()
conn.close()

其他操作(增改删)

sql语句还是自己写,写好占位符,通过 execute 来拼接

conn连接对象.commit() 提交增删改任务

增删改操作的会涉及到数据安全,所以需要写上 conn.commit() 来“确认”提交

亦或是实例化连接时指定参数 autocommit=True

import pymysql

conn = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
password='000000',
database='day38',
charset='utf8', # 编码千万不要加 - --> utf-8 会直接报错
autocommit=True, # 这个参数配置完后,增删改操作都不需要手动加 conn.commit 了
) cursor = conn.cursor() # # sql = "insert into user values(name, password) values('jerry', '666')"
# sql = "update user set name='jason' where id = 1"
#
# res = cursor.execute(sql)
# conn.commit() # 增删改必须有这一句才能完成 pymysql.connect(.....) 里写了这就不用写了 sql = "insert into user (name, password) values (%s, %s)"
# ---------------------------------------------------
# cursor.executemany() 自动拼接sql 语句并执行
# 自动识别 %s 替换成后面的参数,插入多个数据
# ---------------------------------------------------
res = cursor.executemany(sql, [('jerry', '123'), ('tank', '123'), ('jason', '123')]) # ---------------------------------------------------
# conn.commit() 提交 新增、修改、删除操作 必须写上才有效
# ---------------------------------------------------
conn.commit() cursor.close()
conn.close()

防注入的登录功能

import pymysql

conn = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
password='000000',
database='day38',
charset='utf8' # 编码千万不要加 - --> utf-8 会直接报错
) cursor = conn.cursor(pymysql.cursors.DictCursor) username = input("username>>>: ").strip()
password = input("password>>>: ").strip sql = "select * from user where name = %s and password = %s"
# print(sql) res = cursor.execute(sql, [username, password]) if res:
print(cursor.fetchone())
else:
print("用户名或密码错误") cursor.close()
conn.close()

扩展点 utf8mb4

utf8mb4 这个字符编码可以存表情,后期微信小程序可能会弄到

MySQL-注释-Navicat基本使用-复杂查询练习题-解题思路-pymysql操作数据库-SQL注入-05的更多相关文章

  1. 第二百八十一节,MySQL数据库-SQL注入和pymysql模块防止SQL注入

    MySQL数据库-SQL注入和pymysql模块防止SQL注入 SQL注入就是通过SQL语句绕开程序判断,获取到数据库的内容 下面以一个简单的程序登录SQL注入举例: 正常登录 1.数据库有一张会员表 ...

  2. 数据库——可视化工具Navicat、pymysql模块、sql注入问题

    数据库--可视化工具Navicat.pymysql模块.sql注入问题 Navicat可视化工具 Navicat是数据库的一个可视化工具,可直接在百度搜索下载安装,它可以通过鼠标"点点点&q ...

  3. MySQL的操作数据库SQL语法

    MySQL的操作数据库SQL语法 顺序:操作数据库 > 操作数据库中的表 > 操作数据库中的表的数据 MySQL不区分大小写字母 1. 操作数据库 1.创建数据库 2.删除数据库 3.使用 ...

  4. HAVING,多表查询思路,可视化软件navicat,多表查询练习题,

    HAVING "where"是一个约束声明,在查询数据库的结果返回之前对数据库中的查询条件进行约束,即在结果返回之 前起作用,且"where"后面不能写&quo ...

  5. mysql 使用Navicat Lite如何打开‘查询编辑器’,使用sql语句对表进行操作!

    今天第一次使用mysql,尽然连查询编辑器都找不到,研究了半天,询问了下大牛,才搞出来,准备写下来,后面方面忘记了有查找的地方,哈哈哈~~ 如何打开"查询编辑器",使用sql语句进 ...

  6. MySQL&SQL server&Oracle&Access&PostgreSQL数据库sql注入详解

    判断数据库的类型 当我们通过一些测试,发现存在SQL注入之后,首先要做的就是判断数据库的类型. 常用的数据库有MySQL.Access.SQLServer.Oracle.PostgreSQL.虽然绝大 ...

  7. python连接MySQL pymysql模块,游标,SQL注入问题,增删改查操作

    pymysql模块 pymysql是用python控制终端对MySQL数据库进行操作的第三方模块 import pymysql # 1.连接数据库 client = pymysql.connect( ...

  8. python操作mysql代码讲解(及其实用,未来测试工作主要操作数据库的方法)

    pymsql pymsql是Python中操作MySQL的模块,其使用方法和MySQLdb几乎相同. 下载安装 1 pip3 install pymysql 使用操作 1.执行SQL 1 2 3 4 ...

  9. Day4 数据库的建立||数据库对外查询||使用命令行来操作数据库

    ###数据库的创建 建立一个项目 先进行测试,测试新项目是否可以成功运行 创建一个PersonContrary包,并建立一个Person类实现BaseColumns借口,在此类中添加所有的表的列名,并 ...

随机推荐

  1. LeetCode——372. Super Pow

    题目链接:https://leetcode.com/problems/super-pow/description/ Your task is to calculate ab mod 1337 wher ...

  2. Sublime Text3激活及个性化配置

    [TOC] 在我们的开发过程中,选择正确的开发工具会让我们事半功倍.作为后端开发我们熟悉的myeclipse和itellij idea这些工具我也介绍曾介绍过关于他们的安装及破解.但是我们并不能仅仅使 ...

  3. Hadoop - YARN Introduce

    YARN Introduce 1. MapReduce1.0缺陷 (1)存在单点故障 (2)JobTracker"大包大揽"导致任务过重(任务多时内存开销大,上限4000节点) ( ...

  4. c#Winform自定义控件-目录

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control ...

  5. python(自用手册)导图

  6. 驰骋工作流引擎ccflow-流转自定义功能使用说明

    流转自定义功能使用说明 关键字: 驰骋工作流程快速开发平台 工作流程管理系统 工作流引擎 asp.net工作流引擎 java工作流引擎. 节点跳转 节点流转自定义 应用背景: 有一些流程在运行过程中是 ...

  7. Docker:镜像的迁移

    从202将现有镜像搬到207的过程. 先说导出,两种方法:Docker save 和 docker export,前者保存镜像,后者导出容器. docker save docker.io/java:7 ...

  8. 使用Python的Django和layim实现即时通讯

    看到Django和layim实现websocketde资料很少,自己就琢磨了下,顺便搭建出来了.自己要去找闲心大神授权呀. 先来看图  这是初次搭建的,今天一天就搞定.我自己接入了图灵机器人. Pyt ...

  9. 对IOC和DI的通俗理解

    学习过spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的,今天和大家 ...

  10. MSIL实用指南-逻辑运算

    逻辑运算有三种:与.或.非.实现它们可以用位运算指令And.Or.Not等三个指令.它们的使用方法和位运算一致. 完整的程序如下: using System; using System.Reflect ...