mysql之子查询、视图、事务及pymysql等
数据准备
CREATE TABLE `emp` (
`id` int(0) NOT NULL AUTO_INCREMENT,
`name` varchar(10) NOT NULL,
`gender` enum('男','女','未知') NULL DEFAULT '未知',
`age` int(0) NULL DEFAULT 0,
`salary` float NULL DEFAULT 0,
`area` varchar(20) NULL DEFAULT '中国',
`port` varchar(20) DEFAULT '未知',
`dep` varchar(20),
PRIMARY KEY (`id`)
);
INSERT INTO `emp` VALUES
(1, 'yangsir', '男', 42, 10.5, '上海', '浦东', '市场部'),
(2, 'engon', '男', 38, 9.4, '山东', '济南', '研发部'),
(3, 'jerry', '女', 30, 3.0, '江苏', '张家港', '研发部'),
(4, 'tank', '女', 28, 2.4, '广州', '广东', '研发部'),
(5, 'jiboy', '男', 28, 2.4, '江苏', '苏州', '研发部'),
(6, 'zero', '男', 18, 8.8, '中国', '黄浦', '销售部'),
(7, 'owen', '男', 18, 8.8, '安徽', '宣城', '研发部'),
(8, 'jason', '男', 28, 9.8, '安徽', '巢湖', '研发部'),
(9, 'ying', '女', 36, 1.2, '安徽', '芜湖', '销售部'),
(10, 'kevin', '男', 36, 5.8, '山东', '济南', '研发部'),
(11, 'monkey', '女', 28, 1.2, '山东', '青岛', '市场部'),
(12, 'san', '男', 30, 9.0, '上海', '浦东', '销售部'),
(13, 'san1', '男', 30, 6.0, '上海', '浦东', '销售部'),
(14, 'san2', '男', 30, 6.0, '上海', '浦西', '研发部'),
(15, 'ruakei', '女', 67, 2.501, '上海', '陆家嘴', '研发部');
联合分组
# 数据来源:在单表emp下
# 联合分组:按多个字段综合结果进行分组,其实就是group by 后面跟多个值
# 按 area与port组合后的结果进行分组,只有组合后的结果还一致,才认为是一组
select group_concat(name),area,port from emp group by area,port;
#例如 上海-浦东的才算是一组,上海浦西的算一组
select group_concat(name),area from emp group by area;
# 会把area相同的分成一组,例如 上海的一组,山东的一组
子查询
# 增:insert into 表 select子查询
# 删:delete from 表 条件是select子查询(表不能与delete表相同)(不能查的同时删除)
# 查:select 字段 from 表 条件是select子查询
# 改:update 表 set 字段=值 条件是select子查询(表不能与update表相同)(不能查的时候同时修改)
# 数据来源:在单表emp下
# 子查询:将一条查询sql的结果作为另一条sql的条件
##############
####### 思考:每个部门最高薪资的那个人所有信息##########
#############
# 子查询的sql
select dep, max(salary) from emp group by dep;
# 子查询 - 查
select * from emp where (dep, salary) in (select dep, max(salary) from emp group by dep);
#按部门分组,先查最高薪资和部门,在在里面把所有信息打印处理
# 将子查询转换为一张表
# 创建一个存子查询数据的一张表
create table t1(dep_name varchar(64), max_salary decimal(5,2));
# 子查询 - 增
insert into t1 select dep, max(salary) from emp group by dep;
###insert into 表名 select 子查询语句
# 需求
select name, dep_name, salary
from emp join t1
on emp.dep=t1.dep_name and emp.salary=t1.max_salary;
#把子查询的结果增加到原表中,需要重新创建一个表用于保存子查询表的结果,
#需要进行连接,按照工资和部门进行join
# 子查询 - 改(update更新的表不能 与 子查询select的表同表)
# 每个部门最大薪资+1
update t1 set max_salary=max_salary+1;
# 给t1额外增加一个新部门
insert into t1 values ('打杂部', 100);
# 子查询 - 改
update t1 set max_salary=max_salary+1 where dep_name in (select distinct dep from emp);
# 错误:update更新的表 与 子查询select的表 相同
update t1 set max_salary=max_salary+1 where dep_name in (select distinct dep_name from t1);
# 子查询 - 删
delete from t1 where dep_name in (select distinct dep from emp);
# 错误: delete删除的表 与 子查询select的表 相同(报错You can't specify target table 't1' for update in FROM clause)
delete from t1 where dep_name in (select distinct dep_name from t1);
all与any:区间修饰条件
# 语法规则
# where id in (1, 2, 3) => id是1或2或3
# where id not in (1, 2, 3) => id不是1,2,3
# where salary < all(3, 6, 9) => salary必须小于所有情况(小于最小)
# where salary > all(3, 6, 9) => salary必须大于所有情况(大于最大)
# where salary < any(3, 6, 9) => salary只要小于一种情况(小于最大)
# where salary > any(3, 6, 9) => salary只要大于一种情况(大于最小)
in < > ()
# 案例
select * from emp where salary < all(select salary from emp where id>11);
视图:view
# 数据依赖:单表emp
"""
1)视图是存在内存中的临时表
2)视图的创建依赖select语句,所有就是select语句操作的结果形成的表
3)视图支持对数据的增删查改 ?
4)视图不允许对视图表的字段做修改
5)视图不仅支持创建,也支持更新与删除
"""
# 语法
# 创建视图(视图是可以临时存储起来的)
mysql>: create view 视图名[(别名们)] as select 语句;
eg>: create view v1 as select dep, max(salary) from emp group by dep;
#和表结构内容相同
# 创建或替换视图
mysql>: create or replace 视图名[(别名们)] as select 语句;
#存在就替换,不存在就创建,所以这个命令是常用的
mysql>: alter 视图名[(别名们)] as select 语句;
eg>: create or replace view v1(dep_name, max_salary) as select dep, max(salary) from emp group by dep;
eg>: alter view v1(name, salary) as select dep, max(salary) from emp group by dep;
# 删除视图
mysql>: drop view 视图名
eg>: drop view v1;
# 视图可以作为正常表完成连表查询
select name, dep_name, salary
from emp join v1
on emp.dep=v1.dep_name and emp.salary=v1.max_salary;
#创建视图的时候要改个名字,不然就连不起来
视图的增删改
# 前提:视图的增删改操作可以直接映射给真实表(本质就是对真实表进行操作)
# 视图可以完成增删改,增删改本质是直接对创建视图的真实表进行操作
create or replace view v2 as select id,name,age,salary from emp;
update v2 set salary=salary+1 where id=1;
delete from v2 where id=1;
create or replace view v3 as select * from emp;
insert into v3 values(1, 'yangsir', '男', 66, 1.11, '上海', '那噶的', '教职部');
# 总结:操作视图,会影响真实表,反之也会影响
update emp set salary=salary+1 where id=1;
事务
# 事务:通常一些业务需要多条sql参与,参与的sql会形成一个执行整体,该整体我们就称之为 事务
# 简而言之:事务 - 就是多条执行的sql语句
# 比如:转账就是一个事务:从一个用户将资金转出,再将资金转入到另一个用户
""" 事务的四大特性(必须全部满足)
1.原子性:事务是一组不可分割的单位,要么同时成功,要么同时不成功
2.一致性:事务前后的数据完整性应该保持一致(数据库的完整性:如果数据库在某一时间点下,所有的数据都符合所有的约束,则称数据库为完整性的状态)
3.隔离性:事务的隔离性是指多个用户并发访问数据时,一个用户的事物不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离
4.持久性:持久性是指一个事物一旦被提交,它对数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响
"""
# mysql中事务的执行
create table bank(
id int,
name varchar(16),
money decimal(65, 2)
);
insert into bank values(1, 'Tom', 10), (2, "Bob", 10);
# 假设出现以下执行情况
# 没有事务支持情况下,Tom的钱就丢了,没有ruakei这个人,所以就转没了
update bank set money=money-1 where name='Tom';
update bank set money=money+1 where name='ruakei';
# 将两条sql看做事务处理
# 开启事务
begin;
update bank set money=money-1 where name='Tom';
update bank set money=money+1 where name='ruakei';
# 确认无误,提交事务
commit;
# 确认有误,回滚(相当于撤回,会把数据恢复到操作前的模样)
rollback;
pymysql:
python操作mysql
# 选取操作的模块 pymysql
# pymysql连接数据库的必要参数:主机、端口、用户名、密码、数据库
# 注:pymysql不能提供创建数据库的服务,数据库要提前创建
import pymysql
'''
1)建立数据库连接对象 conn
2)通过 conn 创建操作sql的 游标对象
3)编写sql交给 cursor 执行
4)如果是查询,通过 cursor对象 获取结果
5)操作完毕,端口操作与连接
'''
# 1. 建立数据库连接对象,参数必须要填写的是用户名、密码、数据库名,且参数名要确定(去源码里面可以看得到),
# autocommint默认是False,为True的话,表示自动变为事务语句
conn = pymysql.connect(user = 'root', passwd='root', database = 'hupu')
# conn = pymysql.connect(user = 'root', passwd='root', database = 'hupu', autocommit=True)
# 2.通过 conn 创建操作sql 的游标对象
# 注:游标不设置参数,查询的结果就是数据元组,数据没有标识性
# 设置pymysql.cursor.DictCursor,查询的结果是字典,key是表的字段
cursor = conn.cursor(pymysql.cursors.DictCursor)
# cursor = conn.cursor() #这样的话就是元组,没有键,只有值,所以没有标识性
# sql1 = 'create table t1(id int, x int, y int)'
# cursor.execute(sql1)
# 编写sql语句交给 cursor 执行
# 增
# sql2 = 'insert into t1 values(%s, %s, %s)'
# cursor.executemany(sql2, [(1, 10, 100),(2, 20, 200)])
# cursor.execute(sql2, (3, 10, 100))
#只写这句话的话,select * from t1,查不到任何数据,原因是不设置commit,
# 默认开启事务,增删改操作不会直接映射到数据库中,需要执行 conn.commit()
# conn.commit()
#就有数据了
# 删
# sql3 = 'delete from t1 where id=%s'
#
# cursor.execute(sql3, 3)
# conn.commit()
# 查
sql5 = 'select * from t1'
row = cursor.execute(sql5) # 返回值是受影响的行
print(row)
# 4)如果是查询,通过 cursor对象 获取结果
'''
1. fetchone() 偏移一条取出
2. fetchmany(n) 偏移n条取出
3. fetchall() 偏移剩余全部
'''
r1 = cursor.fetchone() #要和查语句进行连用
r2 = cursor.fetchone()
r3 = cursor.fetchmany(2) #紧接着选择两条
r4 = cursor.fetchall()
print(r1)
print(r2)
print(r3)
print(r4)
# 5)操作完毕,端口操作与连接
cursor.close()
conn.close()
游标操作
import pymysql
from pymysql.cursors import DictCursor
#连接数据库,获取数据库对象conn
conn = pymysql.connect(user = 'root', passwd = 'root', db='hupu')
#通过 conn 创建操作sql的游标对象
cursor = conn.cursor(DictCursor)
#编写sql语句,交给cursor游标实现
sql3 = 'select * from t12'
# sql2 = 'create table t12(id int, x int, y int)'
# cursor.execute(sql2)
# sql3 = 'insert into t12 values(%s, %s, %s)'
# cursor.executemany(sql3, [(1, 10, 100), (2, 20, 200), (3, 30, 300), (4, 40, 400)])
#如果是查询,通过 cursor 对象,获取结果
row = cursor.execute(sql3)
if row:
r1 = cursor.fetchmany(2)
print(r1)
# 操作游标
cursor.scroll(2, 'absolute') #绝对路径, 从第一个开始按顺序往下找2个
# cursor.scroll(1, 'relative') #相对路径,往下1个
# cursor.scroll(-1, 'relative')
r2 = cursor.fetchone()
print(r2)
# 操作完毕,端口操作与连接
cursor.close()
conn.close()
sql注入
import pymysql
from pymysql.cursors import DictCursor
conn = pymysql.connect(user='root', passwd='root', db='hupu')
cursor = conn.cursor(DictCursor)
try:
sql = 'create table user(id int, name char(4), password char(6))'
row = cursor.execute(sql)
print(row)
except:
print('表已创建')
pass
# 空表才插入
row = cursor.execute('select * from user')
#就像我们在cmd中创建表一样,创建成功会有提示,几个rows affected(0 rows affected),这里就用于接收这个返回
if not row:
sql = 'insert into user values(%s,%s,%s)'
row = cursor.executemany(sql, [(1, 'tom', '123'), (2, 'bob', 'abc')])
conn.commit()
# 用户登录
usr = input('usr: ')
pwd = input('pwd: ')
# 输入用户时:
# tom => select * from user where name="tom" and password="%s"
# tom" # => select * from user where name="tom" #" and password="%s"
# (加引号的作用就是把tom加进去了,前面是一段完整的句子,后面全是注释,随便输入就能登录成功)
# 不自定义用户名时
# " or 1=1 # => select * from user where name="" or 1=1 #" and password="%s"
# (加引号的作用就是把 前面的句子和1=1进行or 逻辑运算
# 这样后者肯定成立,再在后面加# 注释,密码随便输入就可以成功了
# sql = 'select * from user where name="%s" and password="%s"' % (usr, pwd) #自己拼接
# row = cursor.execute(sql)
# if row:
# print('登录成功')
# else:
# print('登录失败')
# 由上面的语句可以看出,自己拼接参数一定有sql注入,将数据的占位填充交给pymysql,就能解决sql诸如问题
sql = 'select * from user where name=%s and password=%s'
row = cursor.execute(sql, (usr, pwd))
if row:
print('登录成功')
else:
print('登录失败')
事务
import pymysql
from pymysql.cursors import DictCursor
conn = pymysql.connect(user='root', passwd='root', db='hupu')
cursor = conn.cursor(DictCursor)
#判断表是否创建的异常
try:
sql = 'create table t2(id int, name char(4), money int)'
row = cursor.execute(sql)
print(row) #创建表,受影响的行是0
except:
print('表已创建')
pass
# 空表才插入
row = cursor.execute('select * from t2')
if not row:#如果创建成功,就往里面插入值
sql = 'insert into t2 values(%s,%s,%s)'
row = cursor.executemany(sql, [(1, 'tom', 10), (2, 'Bob', 10)])
conn.commit()
#转给不存在的用户,就会走异常那个流程
try:
sql1 = 'update t2 set money=money-1 where name="tom"'
r1 = cursor.execute(sql1)
sql2 = 'update t2 set money=money+1 where name="ruakei"' # 转入的人不存在
r2 = cursor.execute(sql2)
except:
print('转账执行异常')
conn.rollback() #转账存在异常的话就要进行回滚了
else:
print('转账没有异常')
if r1 == 1 and r2 == 1:
print('转账成功')
conn.commit()
else:
conn.rollback()
索引
# 索引就是 键 - key
"""
1)键 是添加给数据库表的 字段 的
2)给表创建 键 后,该表不仅会形成
表结构、表数据,还有 键的B+结构图
3)键的结构图是需要维护的,在数据完成
增、删、改操作时,只要影响到有键的字段,
结构图都要维护一次
所以创建键后一定会降低 增、删、改 的效率
4)键可以极大的加快查询速度(开发需求中,几
乎业务都和查有关系)
5)建立键的方式:主键、外键、唯一键、index
"""
import pymysql
from pymysql.cursors import DictCursor
conn = pymysql.connect(user='root', passwd='root', db='hupu')
cursor = conn.cursor(DictCursor)
# # 创建两张表
# sql1 = """create table a1(
# id int primary key auto_increment,
# x int,
# y int
# )"""
# cursor.execute(sql1)
# sql2 = """create table a2(
# id int primary key auto_increment,
# x int,
# y int,
# index(x)
# )"""
# cursor.execute(sql2)
#
# # 每个表插入5000条数据
# import random
# for i in range(1, 5001):
# x = i
# y = random.randint(1000, 5000)
# cursor.execute('insert into a1(x, y) values(%s, %s)'%(x, y))
# cursor.execute('insert into a2(x, y) values(%s, %s)'% (x, y))
# conn.commit()
import time
# a1的x、a1的id、a2的x
b_time = time.time()
sql = 'select * from a1 where id=4975'
cursor.execute(sql)
e_time = time.time()
print(e_time - b_time)
# 0.0010004043579101562
b_time = time.time()
sql = 'select * from a1 where x=4975'
cursor.execute(sql)
e_time = time.time()
print(e_time - b_time)
# 0.0019974708557128906
b_time = time.time()
sql = 'select * from a2 where x=4975'
cursor.execute(sql)
e_time = time.time()
print(e_time - b_time)
# 0.0009984970092773438
mysql之子查询、视图、事务及pymysql等的更多相关文章
- MySQL多表查询、事务、DCL:内含mysql如果忘记密码解决方案
MySQL多表查询.事务.DCL 多表查询 * 查询语法: select 列名列表 from 表名列表 where.... * 准备sql # 创建部门表 CREATE TABLE dept( id ...
- mysql in 子查询 效率慢 优化(转)
mysql in 子查询 效率慢 优化(转) 现在的CMS系统.博客系统.BBS等都喜欢使用标签tag作交叉链接,因此我也尝鲜用了下.但用了后发现我想查询某个tag的文章列表时速度很慢,达到5秒之久! ...
- MySQL 行子查询(转)
MySQL 行子查询 行子查询是指子查询返回的结果集是一行 N 列,该子查询的结果通常是对表的某行数据进行查询而返回的结果集. 一个行子查询的例子如下: SELECT * FROM table1 WH ...
- MySQL FROM 子查询
FROM 子句中的子查询 MySQL FROM 子查询是指 FROM 的子句作为子查询语句,主查询再到子查询结果中获取需要的数据.FROM 子查询语法如下: SELECT ... FROM (subq ...
- MySQL 表子查询
MySQL 表子查询 表子查询是指子查询返回的结果集是 N 行 N 列的一个表数据. MySQL 表子查询实例 下面是用于例子的两张原始数据表: article 表: aid title conten ...
- MySQL 行子查询
MySQL 行子查询 行子查询是指子查询返回的结果集是一行 N 列,该子查询的结果通常是对表的某行数据进行查询而返回的结果集. 一个行子查询的例子如下: SELECT * FROM table1 WH ...
- Mysql in子查询中加limit报错
Mysql in子查询中加limit报错 select id from aa where id in ( select id from bb limit 10 ); 改写成 SELECT id FRO ...
- mySQL多表查询与事务
一.范式 1. 什么是范式 1.1 什么是范式 范式:设置一个科学的.规范的数据库,需要满足的一些规则 1.2 有哪些范式 共有:6大范式 第1范式:1NF 满足最基本的要求 第2范式:2NF 在1N ...
- MySQL 多表查询与事务的操作
表连接查询 什么是多表查询 # 数据准备 # 多表查询的作用 * 比如:我们想查询孙悟空的名字和他所在的部门的名字,则需要使用多表查询 # 如果一条 SQL 语句查询多张表,因为查询结果在多张不同的表 ...
随机推荐
- Visual Studio 调试系列4 单步后退来检查旧应用状态(使用使用 IntelliTrace 窗口)
系列目录 [已更新最新开发文章,点击查看详细] IntelliTrace 后退会在每个断点处及调试器步骤事件发生时自动拍摄应用程序的快照. 凭借记录的快照便可以返回到上一个断点或步骤,并查看当 ...
- Qt Quick 事件处理之鼠标、键盘、定时
一.鼠标事件 MouseArea 对象可以附加到一个 item 上供 item 处理鼠标事件,它本身是一个不可见的 item .在其内部,可以直接引用它所附着的对象的属性和方法.你可以将 MouseA ...
- 破解Xmind时长
第一步:必须先进入软件,新建一个思维导图,产生用户状态文件就行. 直接软解: 第二步:打开路径:C:\Users\你的电脑名称\AppData\Roaming\XMind ZEN\Electron v ...
- SpringBoot第十篇:thymeleaf详解
作者:追梦1819 原文:https://www.cnblogs.com/yanfei1819/p/10931435.html 版权声明:本文为博主原创文章,转载请附上博文链接! 引言 Sprin ...
- FutureTask源码2
@SuppressWarnings({"unchecked","restriction"}) public class FutureTask1<V> ...
- ThinkPHP连接Oracle数据库的详细教程
一. 操作环境搭建 系统:Windows7 旗舰版 64位PHP环境:wampserver2.2e-php5.4.3-httpd2.2.22-mysql5.5.24 32位版ThinkPHP:3.0正 ...
- git 版本(commit) 回退 -- 使用git reset 指令
刚刚提交了三个commit, git reflog显示如下: 最后一个commit在文件末尾加了一行:v3,以此类推: 下面,使用git reset --hard commitID来进行commit回 ...
- java线程锁基础
定义运行方法 package com.company; // 包名import java.util.concurrent.locks.ReentrantLock;import java.util.co ...
- .net持续集成cake篇之常见文件及路径操作
系列目录 Cake常见文件和路径操作 在自动化构建任务里,很多操作都是跟文件打交道,比如文件打包,文件压缩,文件归档,文件传输,目录清理等.本节介绍一些cake里常见的文件操作方法 Cake相对路径问 ...
- NIO ByteBuffer的allocate与allocateDirect区别(HeapByteBuffer与DirectByteBuffer的区别)
在Java中当我们要对数据进行更底层的操作时,一般是操作数据的字节(byte)形式,这时经常会用到ByteBuffer这样一个类. ByteBuffer提供了两种静态实例方式: public stat ...