第四天(41道题全解) sql注入
41道题:
重要的 连表查询 分组 制表语句: 班级表 Table: class Create Table: CREATE TABLE `class` ( `cid` int(11) NOT NULL AUTO_INCREMENT, `caption` varchar(50) DEFAULT NULL, PRIMARY KEY (`cid`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 1 row in set (0.00 sec) 学生表: Table: student Create Table: CREATE TABLE `student` ( `sid` int(11) NOT NULL AUTO_INCREMENT, `sname` varchar(50) DEFAULT NULL, `gender` char(10) DEFAULT NULL, `class_id` int(11) DEFAULT NULL, PRIMARY KEY (`sid`), KEY `fk_student_class` (`class_id`), CONSTRAINT `fk_student_class` FOREIGN KEY (`class_id`) REFERENCES `class` (`cid`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 老师表: Table: teacher Create Table: CREATE TABLE `teacher` ( `tid` int(11) NOT NULL AUTO_INCREMENT, `tname` varchar(50) DEFAULT NULL, PRIMARY KEY (`tid`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 1 row in set (0.00 sec) 课程表: Table: course Create Table: CREATE TABLE `course` ( `cid` int(11) NOT NULL AUTO_INCREMENT, `cname` char(25) DEFAULT NULL, `teacher_id` int(11) DEFAULT 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=4 DEFAULT CHARSET=utf8 1 row in set (0.00 sec) 成绩表: create table score (sid int not null auto_increment primary key, student_id int not null, corse_id int not null, number int not null, unique uq_sc (student_id,corse_id), CONSTRAINT fk_sc_st FOREIGN key (student_id) REFERENCES student(sid), constraint fk_sc_co foreign key (corse_id) references course(cid) ) engine=innodb default charset=utf8; group by前面的slect 只能用聚合函数count,max什么的 v= 111 if 1==1 else 110 三元运算符 ######################################################### 作业练习: http://www.cnblogs.com/wupeiqi/articles/5729934.html http://www.cnblogs.com/wupeiqi/p/5748496.html 参考答案 ########################################################## 用到的知识点 - 临时表 select * from (select * from tb where id< 10) as B; --- select id, name, 1, (select count(1) from tb)----只要拿到的是一个值就可以 from tb2 ---把最外层的表s1,每次循环取一个常量值再到每一列中再循环一次 SELECT student_id, (select num from score as s2 where s2.student_id=s1.student_id and course_id = 1) as 语文, (select num from score as s2 where s2.student_id=s1.student_id and course_id = 2) as 数学, (select num from score as s2 where s2.student_id=s1.student_id and course_id = 3) as 英语 from score as s1; ----avg(if(isnull(score.num),0,score.num)) 三目运算符 ##################################################### 具体作业: 1、自行创建测试数据 2、查询“生物”课程比“物理”课程成绩高的所有学生的学号; PS:查出生物课程的学生,查出物理课程的学生,用临时表,再连接查询 select A.student_id from (select * from score LEFT JOIN course on score.course_id=course.cid where course.cname="生物" ) as A LEFT JOIN (select * from score LEFT JOIN course on score.course_id=course.cid where course.cname="物理" ) as B on A.student_id=B.student_id where A.num> B.num 3、查询平均成绩大于60分的同学的学号和平均成绩; select student_id, avg(num) from score GROUP BY student_id PS:把名字也带上 select S.student_id,student.sname,S.av_s from (SELECT student_id, avg(num) AS av_s FROM score GROUP BY student_id HAVING av_s > 60) as S LEFT JOIN student on student.sid=S.student_id 4、查询所有同学的学号、姓名、选课数、总成绩; SELECT score.student_id,student.sname, COUNT(score.student_id),sum(score.num) from score LEFT JOIN student ON score.student_id=student.sid GROUP BY score.student_id 5、查询姓“李”的老师的个数; select COUNT(*) from teacher where teacher.tname LIKE "李%" 6、查询没学过“李平老师“课的同学的学号、姓名; PS:先查找李平的课程ID,再到score表中找学他的课的学生Id,再去student表中全部排除 select student.sid,student.sname from student where student.sid not in ( select score.student_id from score where course_id in (select course.cid from course LEFT JOIN teacher on teacher.tid=course.cid where teacher.tname="李平老师") ) 7、查询学过“001”并且也学过编号“002”课程的同学的学号、姓名; PS:找出score表中学过课程1,或者2,或者1,2的学生,分组找出大于2的,再与学生表进行连接查询 select student.sid,student.sname from score LEFT JOIN student on score.student_id=student.sid where score.course_id=1 or score.course_id=2 GROUP BY score.student_id HAVING count(score.course_id)>1 8、查询学过“叶平”老师所教的所有课的同学的学号、姓名; PS:语句分两部分B表是查出学过叶平老师所有课程的学生ID(注意其中叶平的课程有所变化所以不能count >2) 再与学生表进行关联 SELECT student.sid,student.sname FROM student LEFT JOIN ( SELECT score.student_id FROM score WHERE score.course_id IN ( SELECT cid FROM course LEFT JOIN teacher ON teacher.tid = course.teacher_id WHERE teacher.tname = "李平老师" ) --查出叶平老师所教的课程的ID GROUP BY score.student_id HAVING count(score.student_id) = ( SELECT count(cid) FROM course LEFT JOIN teacher ON teacher.tid = course.teacher_id WHERE teacher.tname = "李平老师" ) --查出叶平老师总共教了几门课count(cid) ) AS B --查出学过叶平老师所有课程的学生ID ON student.sid = B.student_id 9、查询课程编号“002”的成绩比课程编号“001”课程低的所有同学的学号、姓名; PS: select student.sid,student.sname from student left JOIN (select A.student_id from (select * from score LEFT JOIN course on score.course_id=course.cid where course.cid=1 ) as A LEFT JOIN (select * from score LEFT JOIN course on score.course_id=course.cid where course.cid=2 ) as B on A.student_id=B.student_id where A.num<B.num ) as C on student.sid=C.student_id 10、查询有课程成绩小于60分的同学的学号、姓名; select sid,sname from student where sid in ( select distinct student_id from score where num < 60 ) 11、查询没有学全所有课的同学的学号、姓名; PS ---count要嘛用1要嘛用主键,效率高 SELECT student.sid,student.sname from student INNER JOIN ( select score.student_id,count(1) from score GROUP BY score.student_id HAVING count(1) < (SELECT count(cid) from course) ) as B on student.sid = B.student_id 12、查询至少有一门课与学号为“001”的同学所学相同的同学的学号和姓名; select student.sid,student.sname from student INNER JOIN ( SELECT score.student_id,score.course_id from score where score.student_id !=1 and score.course_id in (select score.course_id from score where score.student_id=1) GROUP BY score.student_id ) as B on student.sid=B.student_id 13、查询至少学过学号为“001”同学所有课的其他同学学号和姓名 select student.sid,student.sname from student INNER JOIN ( SELECT score.student_id,count(1) from score where score.student_id !=1 and score.course_id in (select score.course_id from score where score.student_id=1) GROUP BY score.student_id HAVING count(1) = (select count(1) from score where score.student_id=1) ) AS B on student.sid=B.student_id 14、查询和“002”号的同学学习的课程完全相同的其他同学学号和姓名; SELECT student_id from score where student_id in ( select student_id from score where student_id !=2 GROUP BY student_id HAVING COUNT(1) =(select count(1) from score where student_id=1) ) and course_id in (SELECT course_id from score where student_id =2) GROUP BY student_id HAVING COUNT(1) = (SELECT count(1) from score where student_id) 15、删除学习“叶平”老师课的SC表记录; delete from score where course_id in ( select cid from course left join teacher on course.teacher_id = teacher.tid where teacher.name = '叶平' ) 16、向SC表中插入一些记录,这些记录要求符合以下条件:①没有上过编号“002”课程的同学学号;②插入“002”号课程的平均成绩; insert into score(student_id,course_id,num) VALUES(select student_id,2,(select AVG(num) from score where course_id = 2) from score where course_id !=2) 17、按平均成绩从低到高显示所有学生的“语文”、“数学”、“英语”三门的课程成绩,按如下形式显示: 学生ID,语文,数学,英语,有效课程数,有效平均分; select s1.student_id, (select num from score left join course on score.course_id = course.cid where course.cname = "生物" and score.student_id=s1.student_id) as 生物, (select num from score left join course on score.course_id = course.cid where course.cname = "物理" and score.student_id=s1.student_id) as 物理, (select num from score left join course on score.course_id = course.cid where course.cname = "体育" and score.student_id=s1.student_id) as 体育, count(s1.course_id), avg(s1.num) from score as s1 group by student_id desc 18、查询各科成绩最高和最低的分:以如下形式显示:课程ID,最高分,最低分; SELECT course_id,MAX(num),min(num) from score GROUP BY course_id 19、按各科平均成绩从低到高和及格率的百分数从高到低顺序; select course_id,avg(num), sum(case when num <60 THEN 0 ELSE 1 END),sum(1), sum(case when num <60 THEN 0 ELSE 1 END)/sum(1) as jgl from score GROUP BY course_id order by AVG(num) asc,jgl desc; 20、课程平均分从高到低显示(现实任课老师); select course_id,avg(num),teacher.tname from score LEFT JOIN course on score.course_id=course.cid left JOIN teacher on teacher.tid = course.teacher_id GROUP BY course_id desc select avg(if(isnull(score.num),0,score.num)),teacher.tname from course left join score on course.cid = score.course_id left join teacher on course.teacher_id = teacher.tid group by score.course_id 21、查询各科成绩前三名的记录:(不考虑成绩并列情况) 22、查询每门课程被选修的学生数; SELECT student_id ,count(1) from score GROUP BY course_id HAVING COUNT(1) >5 23、查询出只选修了一门课程的全部学生的学号和姓名; SELECT student.sid,student.sname from student INNER JOIN (SELECT student_id ,count(1) from score GROUP BY student_id HAVING COUNT(1) =1) as B on student.sid=B.student_id 24、查询男生、女生的人数; SELECT gender,COUNT(1) from student GROUP BY gender 25、查询姓“张”的学生名单; SELECT sname from student where sname LIKE "张%" 26、查询同名同姓学生名单,并统计同名人数; SELECT sname,count(1) from student GROUP BY sname 27、查询每门课程的平均成绩,结果按平均成绩升序排列,平均成绩相同时,按课程号降序排列; SELECT course_id,AVG(num) from score GROUP BY score.course_id ORDER BY avg(num) ASC,course_id DESC 28、查询平均成绩大于85的所有学生的学号、姓名和平均成绩; SELECT sid,sname,T.B from student INNER JOIN (SELECT student_id ,avg(if(ISNULL(num) ,0,num)) as B from score GROUP BY student_id HAVING B >85) as T on T.student_id=student.sid 29、查询课程名称为“生物”,且分数低于60的学生姓名和分数; SELECT student.sname,score.num from course LEFT JOIN score on course.cid=score.course_id LEFT JOIN student on student.sid=score.student_id where course.cname='生物' and score.num < 60 30、查询课程编号为003且课程成绩在80分以上的学生的学号和姓名; SELECT student.sname,score.num from course LEFT JOIN score on course.cid=score.course_id LEFT JOIN student on student.sid=score.student_id where course.cid=3 and score.num >80 31、求选了课程的学生人数 SELECT count(DISTINCT(score.student_id)) from score 32、查询选修“李平”老师所授课程的学生中,成绩最高的学生姓名及其成绩; SELECT student.sname,T.num from student INNER JOIN (SELECT * from teacher LEFT JOIN course on teacher.tid=course.teacher_id LEFT JOIN score on score.course_id=course.cid GROUP BY num HAVING teacher.tname="张磊老师" ORDER BY num DESC LIMIT 0,1) as T on student.sid= T.student_id 33、查询各个课程及相应的选修人数; select course.cname,count(1) from score left join course on score.course_id = course.cid group by course_id; 34、查询不同课程但成绩相同的学生的学号、课程号、学生成绩; SELECT DISTINCT s1.student_id,s1.course_id,s1.num from score as s1,score as s2 WHERE s1.sid !=s2.sid and s1.course_id !=s2.course_id and s1.num=s2.num 35、查询每门课程成绩最好的前两名; select score.sid,score.course_id,score.num,T.first_num,T.second_num from score left join ( select sid, (select num from score as s2 where s2.course_id = s1.course_id order by num desc limit 0,1) as first_num, (select num from score as s2 where s2.course_id = s1.course_id order by num desc limit 1,1) as second_num from score as s1 ) as T on score.sid =T.sid where score.num <= T.first_num and score.num >= T.second_num 36、检索至少选修两门课程的学生学号; SELECT student_id from score GROUP BY student_id HAVING count(student_id) >1 37、查询全部学生都选修的课程的课程号和课程名; 38、查询没学过“叶平”老师讲授的任一门课程的学生姓名; PS:先查出学过李平老师任意一门课的学生,包括只选了一门的,然后,全部排除 SELECT student.sid from student WHERE sid not in( SELECT score.student_id from score WHERE course_id in ( SELECT course.cid from course LEFT JOIN teacher on course.teacher_id=teacher.tid WHERE teacher.tname="李平老师" )) 39、查询两门以上不及格课程的同学的学号及其平均成绩; select student_id,count(1) from score where num < 60 group by student_id having count(1) > 2 40、检索“004”课程分数小于60,按分数降序排列的同学学号; select student_id from score where num< 60 and course_id = 4 order by num desc; 41、删除“002”同学的“001”课程的成绩; delete from score where course_id = 1 and student_id = 2
sql注入代码样例:
import pymysql user = input("username:") pwd = input("password:") conn = pymysql.connect(host="localhost",user='root',password='',database="db666") cursor = conn.cursor() sql = "select * from userinfo where username='%s' and password='%s'" %(user,pwd,) # select * from userinfo where username='uu' or 1=1 -- ' and password='%s' #根本的原因是因为有--注释掉后passwor,而1=1是永真,所以一定不能自己来拼接用户名密码 cursor.execute(sql) result = cursor.fetchone() cursor.close() conn.close() if result: print('登录成功') else: print('登录失败')
为防止sql注入应当使用pymysql自带的excute的参数传递,支持字典,列表,字符串
import pymysql user = input("username:") pwd = input("password:") conn = pymysql.connect(host="localhost",user='root',password='',database="db666") cursor = conn.cursor() sql = "select * from userinfo where username=%s and password=%s" #sql = "select * from userinfo where username=%(u)s and password=%(p)s" cursor.execute(sql,user,pwd) #防止sql注入的方法 # cursor.execute(sql,[user,pwd]) # cursor.execute(sql,{'u':user,'p':pwd}) result = cursor.fetchone() cursor.close() conn.close() if result: print('登录成功') else: print('登录失败')
sql多行插入
1 import pymysql 2 3 # 增加,删,该 4 #conn = pymysql.connect(host="localhost",user='root',password='',database="db1") 5 #cursor = conn.cursor() 6 #sql = "insert into userinfo(username,password) values('root','123123')" 7 ## 受影响的行数 8 #r = cursor.execute(sql) 9 # # ****** 10 #conn.commit() 11 #cursor.close() 12 #conn.close() 13 14 conn = pymysql.connect(host="localhost",user='root',password='',database="db1") 15 cursor = conn.cursor() 16 # # sql = "insert into userinfo(username,password) values(%s,%s)" 17 # # cursor.execute(sql,(user,pwd,)) 18 # 19 sql = "insert into userinfo(username,password) values(%s,%s)" 20 # r 是 受影响的行数 21 r = cursor.executemany(sql,[('egon','sb'),('laoyao','BS')]) 22 # # ****** 23 conn.commit() 24 cursor.close() 25 conn.close() 26 "s3.p
pymysql模块:
pip3 install pymysql -i https://pypi.douban.com/simple
Python模块:对数据库进行操作(SQL语句)
1. Python实现用户登录
2. MySQL保存数据
- 连接、关闭(游标)
- execute() -- SQL注入
- 增删改: conn.commit()
- fetchone fetchall
- 获取插入数据自增ID