MySQL&python交互

MySQL&python交互

一、Python操作MySQL步骤(原始的执行SQL语句)

  1. 引入pymysql模块
image.png
from pymysql import *
  1. Connection对象

    • 用于建立与数据库的连接
    • 创建对象:调用connect()方法
    conn = connect(
    host='localhost', port=3306,user='root',password='mysql',database='jing_dong', charset='utf8')
    # host:      连接mysql主机IP地址
    # port:      连接的mysql主机的端口,默认是3306
    # database: 数据库的名称
    # user:  连接的用户名
    # password: 连接密码
    # charset:   通信的编码方式
    

    对象的方法

    conn.close()     # 关闭连接
    conn.commit()    # 提交
    conn.cursor()    # 返回cursor对象,用于执行sql语句并获取结果
    
  1. Cursor对象

    • 用于执行SQL语句,使用频度最高的语句为select、insert、update、delete
    • 获取Cursor对象:调用Connection对象的cursor()方法
    cs1 = conn.cursor()
    # 执行sql语句
    rows = cs1.execute("""select * from goods;""")
    print(rows)  # rows:影响的数据库行数
    
  2. 对象的方法

    cs1.close()  # 关闭数据库的查询连接
    cs1.execute()    # 执行sql语句,返回受影响的行数
    cs1.fetchone()   # 执行查询语句时,获取查询结果集的第一个行数据,返回一个元祖
    cs1.fetchall()   # 执行查询时,获取查询结果集的所有行,一行构成一个元祖,在将这些元祖祖入一个元祖返回
    
  3. 对象的属性

    cs1.rowcount     # 只读属性,表示最近一次execute()执行后受影响的行数
    cs1.connection       # 获得当前连接对象
    

二、Mysql与Flask的交互

  • Flask提供了扩展Flask-SQLAlchemy,对其交互,操作数据库,是一个简化SQLALchemy操作的扩展
  • SQLALchemy 实际是对数据库的抽象,不使用SQL语句,通过Python对象来操作数据库。
  • SQLALchemy 是一个关系型数据库框架,提供了高层的ORM和底层的原生数据库的操作。
  1. 安装

    pip install flask-sqlalchemy
    # 如果连接的是mysql数据库,需要安装mysqldb
    pip insstall flask-mysqldb
    
  2. 数据库连接设置

    • 在Flask-SQLAlchemy中,数据库使用URL指定,而且程序使用的数据库必须保存到flask配置对象的SQLALCHEMY_DATABASE_URI键中。
    app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test'
    # 动态追踪修改设置,如未设置只会提示警告,默认是True/设置为False
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    #查询时会显示原始SQL语句
    app.config['SQLALCHEMY_ECHO'] = True
    
    # 文档:http://docs.sqlalchemy.org/en/latest/core/engines.html
    
    db = SQLAlchemy(app) # 要把 app 对象注册到SQLAlchemy中
    
  3. 常用的SQLALchemy字段类型

    Integer      int             普通整数
    String       str             变长字符串
    Text     str             变长字符串,对较长或不限长的字符串做了优化
    Boolean      bool            布尔值
    Date     datetime.date   时间
    Time     datetime.datetime 日期和时间
    
  4. 常用的SQLAlchemy列选项

    • 是对列的约束,字段约束
    选项名 说明
    primary_key 如果为True,代表表的主键
    unique 如果为True,代表这列不允许出现重复的值
    index 如果为True,为这列创建索引,提高查询效率
    nullable 如果为True,允许有空值,如果为False,不允许有空值
    default 为这列定义默认值
  5. 常用的SQLALchemy关系选项

    backref 在关系的另一模型中添加反向引用
    primary join 明确指定两个模型之间使用的联结条件
    uselist 如果为False,不使用列表,而使用标量值
    order_by 指定关系中记录的排序方式
    secondary 指定多对多关系中关系表的名字
    secondary join 在SQLAlchemy中无法自行决定时,指定多对多关系中的二级联结条件
1. 基本演练代码
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

# 链接数据库(数据库地址)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/flask01'
# 自动追踪数据库的修改
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 查询时会显示原始SQL语句
# app.config['SQLALCHEMY_ECHO'] = True
# 先给flask对象设置配置,在传对象数据库--创建SQLAlchemy传入app:目的:获取数据库相关参数
db = SQLAlchemy(app)


class Role(db.Model):
    # 定义表名
    __tablename__ = 'roles'
    # 定义列对象
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    us = db.relationship('User', backref='role')

    # repr()方法显示一个可读字符串
    # 直接对象回车就可以打印返回的数据 __str__的区别print打印实例对象
    def __repr__(self):
        return 'Role:name-%s,id-%s' % (self.name, self.id)


class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True, index=True)
    email = db.Column(db.String(64), unique=True)
    password = db.Column(db.String(64))
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

    def __repr__(self):
        return 'User:name-%s,id-%s' % (self.name, self.id)


@app.route('/')
def hello_world():
    return 'Hello World!'


if __name__ == '__main__':
    # 这两个仅供测试使用,开发上线不能使用
    # 删除所有表的数据
    db.drop_all()
    # 创建新表
    db.create_all()

    # 添加角色数据
    ro1 = Role(name='admin')
    db.session.add(ro1)
    db.session.commit()
    # 再次插入一条数据
    ro2 = Role(name='user')
    db.session.add(ro2)
    db.session.commit()

    # 一次性插入十条数据
    us1 = User(name='wang', email='wang@163.com', password='123456', role_id=ro1.id)
    us2 = User(name='zhang', email='zhang@189.com', password='201512', role_id=ro2.id)
    us3 = User(name='chen', email='chen@126.com', password='987654', role_id=ro2.id)
    us4 = User(name='zhou', email='zhou@163.com', password='456789', role_id=ro1.id)
    us5 = User(name='tang', email='tang@itheima.com', password='158104', role_id=ro2.id)
    us6 = User(name='wu', email='wu@gmail.com', password='5623514', role_id=ro2.id)
    us7 = User(name='qian', email='qian@gmail.com', password='1543567', role_id=ro1.id)
    us8 = User(name='liu', email='liu@itheima.com', password='867322', role_id=ro1.id)
    us9 = User(name='li', email='li@163.com', password='4526342', role_id=ro2.id)
    us10 = User(name='sun', email='sun@163.com', password='235523', role_id=ro2.id)
    db.session.add_all([us1, us2, us3, us4, us5, us6, us7, us8, us9, us10])
    db.session.commit()
    app.run(debug=True)
2.在ipython环境下测试

flask_sqlalchemy中,修改数据库

  1. 会话管理用db.session表示。在数据写入数据库前,要将数据添加到会话中,在调用commit()方法提交会话
  2. 查询操作是通过query 对象操作数据
  3. 增-删-改都需要commit

一、增
In [1]: from day04 import *

In [2]: role = Role(name='admin01')

In [3]: db.session.add(role)

In [4]: db.session.commit()
二、改

In [5]: role.name = 'admin001'

In [6]: db.session.commit()

三、删
In [7]: db.session.delete(role)

In [8]: db.session.commit()

————————————查询------------------------------------------------------------

查看用户对应的角色

from database import *

user查询出来是模型的对象,查询具体的值的时候,使用对象的属性查询属性值

创建出来的每一个模型对象,就是一条数据,数据模型类定义的属性就是模型的字段属性数据

user = User.query.get(1)
user.role.name

user:模型实例对象 role:反向引用的字段属性 name:查询的字段属性

查看管理角色有那些用户

role = Role.query.get(1)
In [7]: role
Out[7]: <Role 1>

In [8]: role.users # 生成对象,在点属性查询结果值
Out[8]: [<User 1>, <User 3>]

In [10]: role.users[1].name
Out[10]: '王五'

增加数据

role = Role(name='admin01')

In [3]: db.session.add(role)

In [4]: db.session.commit()

修改数据

In [3]: role.name='admin01'

In [4]: db.session.commit()

删除数据

In [7]: db.session.delete(role)

In [8]: db.session.commit()

----------------------------------------查询需求----------------------------------------------

1.查询所有用户数据
因为repr可以直接使用对象(User)来查询便于查询
User.query.all()

2.查询有多少个用户
User.query.count()

3.查询第1个用户
User.query.first()

4.查询id为4的用户[3种方式]
User.query.get(4)

过滤器是做数据检索判断,后面要加上执行器

filter的功能比较强大,filter_by的查询功能简单
User.query.filter(User.id==4).all()
User.query.filter_by(id=4).first()

filter的语法格式:
filter_by(属性名=X)
filter(模型名.属性名==X)

5.查询名字结尾字符为g的所有数据[开始/包含]
User.query.filter(User.name.endswith('g')).all() -- 以什么结尾
User.query.filter(User.name.startswith('g')).all() --以什么开始
User.query.filter(User.name.contains('g')).all() --包含

6.查询名字不等于wang的所有数据[2种方式]
6.1 User.query.filter(User.name!='wang').all()
6.2 (不用)
from sqlalchemy import not_
User.query.filter(not_(User.name=='wang')).all()

7.查询名字和邮箱都以 li 开头的所有数据[2种方式]
7.1 User.query.filter(User.name.startswith('li'),User.email.startswith('li')).all()
7.2
8.查询password是 123456 或者 emailitheima.com 结尾的所有数据
from sqlalchemy import or_

User.query.filter(or_(User.password=='123456',User.email.endswith('itheima.com'))).all()

9.查询id为 [1, 3, 5, 7, 9] 的用户列表
User.query.filter(User.id.in_([1, 3, 5, 7, 9])).all()

10.查询name为liu的角色数据
In [16]: user = User.query.filter(User.name=='liu').first()
In [17]: user
Out[17]: User:name-liu,id-8
In [18]: user.role.name
Out[18]: 'admin'

11.查询所有用户数据,并以邮箱排序
User.query.order_by('email').all()

12.每页3个,查询第2页的数据

返回一个Paginate对象,它包含指定范围内的结果

paginate = User.query.paginate(2, 3, False)

In [33]: paginate
Out[33]: <flask_sqlalchemy.Pagination at 0x10e736208>

In [34]: paginate.items # 获取分页的数据
Out[34]: [User: name-zhou id-4, User: name-tang id-5, User: name-wu id-6]

In [35]: paginate.page # 当前页码
Out[35]: 2

In [36]: paginate.pages # 总页码
Out[36]: 4

3. 数据库迁移
  • 在Flask中可以使用Flask-Migrate扩展,来实现数据迁移。并且集成到Flask-Script中,所有操作通过命令就能完成
  • 为了导出数据库迁移命令,Flask-Migrate提供了一个MigrateCommand类,可以附加到flask-script的manager对象上。
pip install flask-migrate

from flask import Flask

from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate,MigrateCommand
from flask_script import Shell,Manager

....
db = SQLAlchemy(app)

#第一个参数是Flask的实例,第二个参数是Sqlalchemy数据库实例
migrate = Migrate(app,db) 

#manager是Flask-Script的实例,这条语句在flask-Script中添加一个db命令
manager.add_command('db',MigrateCommand)

.....
  • 创建迁移脚本

    pyhton database.py db init
    python database.py db migrate -m 'initial migration'
    python database.py db upgrade
    

三、Mysql与Django的交互

  • Django默认初始配置使用sqlite数据库。使用MySQL数据库首先需要安装驱动程序。

  • 在Django的工程同名子目录的init.py文件中添加执行MySQL的执行驱动。

  • 在setting文件中配置DATABASES配置信息

    pip install Pymysql
    # 在__init__文件下
    from pymysql import install_as_MySQLdb
    install_as_MySQLdb()
    
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'HOST': '127.0.0.1',  # 数据库主机
            'PORT': 3306,  # 数据库端口
            'USER': 'root',  # 数据库用户名
            'PASSWORD': 'mysql',  # 数据库用户密码
            'NAME': 'django_demo'  # 数据库名字
        }
    }
    

四、MySQL的SQL语句

基本查询
select id as 序号, name as 名字,gender as 性别 from students;# 给查询字段起别名
select s.id,s.name,s.gender from students as s; # 给表起别名
  1. 消除重复行
    • select 后面列的前面使用 distinct
    select distinct 列1,.... from 表名;
    select distinct gender from students;
    
  2. 条件查询

    • 使用 where子句对表中的数据塞选,结果为true的行会出现在结果集
    seclect * from 表名 where 条件
    
    • where子句后面支持多种运算符,进行条件的处理
    1. 比较运算符 # =、>、>=、<、<=、!=、
    select * from students where age != 18;
    2. 逻辑运算符 # and、or、not
    select * from students where not( age > 18 and gender = "女");
    3. 模糊查询      # like、% 表示任意多个字符、__ 表示一个任意字符
    select * from students where name like '黄%' or name like '%靖';
    4. 范围查询      # in 表示在一个非连续的范围、between...and ...表示在一个连续的范围内
    select * from students where age not between 18 and 34;
    5. 空判断       # is null:判空、is not null:判非空
    select * from students where height is not null and gender=1;
    
  3. 排序

    • 为了方便查看数据,可以对数据进行排序
    select * from 表名 order by  列1 asc|desc, [列2 asc|desc,...]
    # asc:升序;desc:降序
    select * from students where (age between 18 and 34) and gender = "女" order by height desc,age asc,id desc;
    
  4. 聚合函数

    • 为了快速统计
    1. count(*):表示计算总行数,括号中写星与列名,结果是相同的 select count(*) from students;
    2. max(列):表示求此列的最大值  select max(id) from students where gender=2;
    3. min(列):表示求此列的最小值  select min(id) from students where is_delete=0;
    4. sum(列):表示求此列的和    select sum(age) from students where gender=1;
    5. avg(列):表示求此列的平均值 select avg(id) from students where is_delete=0 and gender=2;
    
  5. 分组

    • group by:将查询结果按照1个或多个字段进行分组,字段值相同为一组
    • group by可用于单个字段、多个字段分组 。一般都是和其他函数一起使用
    select 分组字段 from 表名 group by 分组字段;
    select gender,count(*) from students group by gender;
    
    • group by + group_concat()
    # group_concat(字段名):可以作为一个输出字段来使用
    # 表示分组之后,根据分组结果,使用group_concat()来放置每一组的某个字段的值集合
    select gender,group_concat(name) from students group by gender;
    
    • group by + 集合函数
    # 通过group_concat(),可以对统计出来每个分组的某个字段值的集合。通过聚合函数来对 值的集合 操作
    select gender,count(*) from students group by gender;
    
    • group by + having

      having:条件表达式:原来分组查询后指定一些条件输出查询的结果

      having 作用和where一样:但是having只能用在group by

      having 后通常也要跟 聚合函数

    select gender,avg(age),group_concat(name) from students group by gender having avg(age) > 30; # 查询性别分组、分组集合字段有哪些name、对于输出结果判断是否符合 平均年龄大于30
    
    • group by + with rollup
    • with rollup:在最后新增一行,来记录当前列里面所有记录的总和 (汇总的作用)
    select gender,group_concat(age) from students group by gender with rollup;
    
  6. 获取部分行

    • 当数据量较大时,在一页查看数据limit要放到最后
    • 起始位置 = (页面数-1)每一页的个数*
    select * from students where is_delete=0 limit (n-1)*m,m
    
    # start:开始的地方,获取count条数据
    select * from 表名 limit start,count
    select * from students limit 6,2; # 每页显示2个,第4个页面
    select * from students order by age asc limit 10,2 ; # 每页显示2个,第6个页面,按照年龄排序
    
  7. 连接查询

    • mysql支持三种类型的连接查询:
    • 内连接查询:查询结果为两个表的匹配的结果(交集)
    • 右连接查询:查询结果为两个表的匹配的数据,右表特有的数据,对于左表不存在数据使用null填充
    • 左连接查询:查询的结果为两个表匹配到的数据,左表特有的数据,对于右表中不存在的数据使用null填充
    # inner join ... on :on 后面是两个表之间的查询条件
    selcet * from 表1 inner或left或right jion 表2 on 表1.列 = 表2.列
    
    # 查询学生姓名和班级姓名
    select s.name,c.name from student as s inner join classes as c on s.cls_id = c.id
    
  8. 自关联

    • 类似省市区-三级联动的表格设计
    # 1.查询所有的省份
    select * from areas where pid is null;
    # 2.查询某个省份下的所有城市
    select pid from areas where atitle = "河南省"
    select * from areas where pid=(select pid from areas where atitle = "河南省")
    或者:
    select * from areas as a1 inner join areas as a2 on a1.pid=a2.aid where a2.title=".."
    
  9. 子查询

    • in 范围
    主查询 where 条件 in (列子查询)
    # 1.标量 子查询
    select * from students where age > (select avg(age) from students);
    # 2.列级 子查询
    select name from classes where id in (select cls_id from students);
    # 3.行级 子查询
    select * from students where (height,age) = (select max(height),max(age) from students);
    
增加数据
  • 添加数据
格式:insert into 表名(字段...) values(值1...)
insert into students(name,age) values('zhang', '18') # 部分插入数据
insert into students(name) values('李四'),('王五'); # 多行插入数据
修改数据
格式:
update 表名  set 字段 = 值,字段2 = 值2 where 条件;
update user set name='小名';          # 全部修改
update user set name='小明' where id=2;   # 条件修改
update students set gender='男',name='小哈' where id=10;   # 条件修改多个值

五、MySQL的高级使用

1. 视图
  • 视图就是一条select语句执行的结果;作用:就是便于查询
  • 视图是对若干张基本表的引用,一张虚表,查询语句执行的结果(基本表结构发生改变,视图也会改变)
  1. 定义视图
# 创建视图
create view 视图名称 as select语句;   # 视图名称建议使用 v_开头
# 查看视图
show tables;
# 删除视图
drop view 视图名称;
2. 事务命令
  • 注意:修改数据的命令会自动的触发事务,包括insert、update、delete。
  • 手动开启事务原因:可以多次数据修改,要么一起成功,要么一起回滚之前的数据。
# 1. 开启事务
begin;
# 2. 提交事务
commit;
# 3. 回滚
rollback;
2、直接用 SET 来改变 MySQL 的自动 交模式: 
SET AUTOCOMMIT=0 禁止自动 交
SET AUTOCOMMIT=1 开启自动 交
3. 索引
  • 一种特殊的文件(InnoDB数据表上的索引,是表空间的一个组成部分),包含对数据表里面所有记录的引用指针。好比一本书的目录,快速的查询。
  • 在表格上创建唯一的索引。意味着两个行不能拥有相同的索引值。
  1. 索引原理

    1. 索引问题就是一个查找问题。

    2. 数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用 B 树及其变种 B+树。 在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据 结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级 查找算法。这种数据结构,就是索引。

    3. 相当于把数据进行分块整理,从小块中查询数据。

  2. 索引使用

    • 注意:
      1. 建立太多索引将会影响更新和插入速度,索引会占用磁盘空间
    # 1.创建索引
    create index 索引名称 on 表名(字段名称(长度)); # 如果字段是字符串,需要指定长度。与定义时一样
    # 2.查看索引
    show index from 表名;
    # 3.删除索引
    drop index 索引名称 on 表名;
    
    # 查询开启运行时间监测
    set profiling = 1;
    # 查看执行的时间 show profiles;
    
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,392评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,258评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,417评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,992评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,930评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,199评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,652评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,327评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,463评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,382评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,432评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,118评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,704评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,787评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,999评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,476评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,057评论 2 341

推荐阅读更多精彩内容