python连接mysql:增删改查

第一种:用pymysql连接

安装pymysql

conda install pymysql
import pymysql
import pandas as pd
##创建数据库连接,依次是主机名,用户名,密码,要打开的数据库,端口号和编码类型
def get_conn():
    conn = pymysql.connect(
        host="****",
        user="****",
        password="****",
        db="****",
        charset="utf8",
        port=3306,
    )
    # 创建游标:
    cursor = conn.cursor()
    return conn, cursor
def close_conn(conn, cursor):
    if cursor:
        cursor.close()
    if conn:
        conn.close()
def query(sql, *args):
    '''
    :param sql:
    :param args:
    :return:返回结果,提取数据,返回的data是一个二维元组,((),())形式;
    '''
    conn, cursor= get_conn()
    cursor.execute(sql)
    res = cursor.fetchall() # 获取结果
    close_conn(conn, cursor)
    return res
#返回的是所有行在对应列的值
# connect.commit()
#如果对数据进行了增删改查的话,执行该语句,相当于把对数据库的操作提交上去,否则修改不会生效
close_conn(conn, cursor)#当然要有关闭游标和数据库连接的习惯
fetchone与fetchall的理解;举个例子:cursor是我们连接数据库的实例

fetchone()的使用:返回值是单个的元组,也就是一行记录,如果没有结果,那就会返回null

cursor.execute(select username,password,nickname from user where id='%s'  %(input)

result=cursor.fetchone();  此时我们可以通过result[0],result[1],result[2]得到
username,password,nickname

fetchall()的使用:返回值是多个元组,即返回多个行记录,如果没有结果,返回的是()

cursor.execute(select * from user)
result=cursor.fetchall();此时select得到的可能是多行记录,那么我们通过fetchall得到的就是多行记录,
是一个二维元组
((username1,password1,nickname1),(username2,password2,nickname2),(username3,password3,nickname))

第二种:pandas内置的read_sql

需要安装sqlalchemy,但是可以DataFrame的形式读出来,方便多了

conda install sqlalchemy
sql = "select * from employees"
engine = create_engine('mysql+pymysql://root:###@localhost:3306/myemployees?charset=utf8')
#格式一点不能错,依次是用户名,密码(###),主机名,端口号,要连接的数据库,指定编码
df = pd.read_sql(sql,engine)
df#这读出来的是DataFrame,就很开心了
#把上面的语句封装为一个函数,实用些
def reader_sql(query,db='myemployees'):
    sql = query
    engine = create_engine('mysql+pymysql://root:###@localhost:3306/{0}?charset=utf8'.format(db))
    df = pd.read_sql(sql,engine)
    return df
df_employees = reader_sql('select * from employees')#返回结果和上图一样
df_departments = reader_sql('select  * from departments')
df_departments#部门表
merged = pd.merge(df_employees,df_departments,on='department_id')
merged#将来这两个表进行内连接
result = merged.groupby(['department_name','job_id']).count()['employee_id'].reset_index()
result#对部门名和工种进行分组后计数,取员工号这一列的值,重置索引(返回一个DataFrame)
result.to_sql(name='newtable',con=engine,if_exists='append',index=False)
#这里的index如果为True的话也会报错,数据库中没有索引列(建表的时候没有预留索引列的位置)
#默认参数是fail,如果这张表本来存在的话,操作就会fail失败掉
#不建议这种直接建表操作,这样的表中字段类型会有变化,不符合原先数据要求
#建议在workbench中先create table并把所有字段的类型定义好,在使用to_sql进行写入

新建表设置好字段类型后,就可以用to_sql写入了

result.to_sql(name='new_table2',con=engine,if_exists='append',index=False)
#这里注意新建表的时候一定要把各个字段的类型搞准确,编码搞清楚不然没意识到出个错,很难受
#如果重复执行这行代码的话,会导致插入的数据成倍数增加,因为你传入的append参数,会在原数据上接着添加
del result['department_name']#删掉一列后再进行写入
result.to_sql(name='new_table2',con=engine,if_exists='append',index=False)
#如果建表时在NN列未勾选上的话,不会报错,会发现原本的值数量多了一倍,且新增的数据中的department_name列均为空值
#但如果建表时在NN列勾选上的话,表示该字段不允许为空值,就会报错
#还有如果写入的数据字段多了,与建表时给定的字段数量不符也会报错

将excel中分sheet写入数据库

import pymysql
import pandas as pd
from sqlalchemy import create_engine
import xlrd
file = r'C:\Users\谢谢你的爱1998\Desktop\mima-sofia(3).xlsx'
#分sheet写入数据库
# mysql 是数据库; pymysql是你用的连接数据库的库; root对应数据库用户名; root冒号后面写数据库的密码; @符合后面写数据库地址,
# 本地是localhost,3306是端口,trust是数据库名。
# 然后调用df.to_sql()函数将dataframe数据写入:

""" 打开excel表格"""
workbook = xlrd.open_workbook(file)
sheet_names = workbook.sheet_names()
for i in sheet_names :
    data = pd.read_excel(file,sheet_name = i,index = False,encoding='utf-8')
    data.to_sql(i,con=engine,if_exists='replace',index=False)

pd.read_sql()介绍

pandas.read_sql(sql, con, index_col=None, coerce_float=True, params=None, parse_dates=None, columns=None, chunksize=None)

各参数意义

sql:SQL命令字符串
con:连接sql数据库的engine,一般可以用SQLalchemy或者pymysql之类的包建立
index_col: 选择某一列作为index
coerce_float:非常有用,将数字形式的字符串直接以float型读入
parse_dates:将某一列日期型字符串转换为datetime型数据,与pd.to_datetime函数功能类似。可以直接提供需要转换的列名以默认的日期形式转换,也可以用字典的格式提供列名和转换的日期格式,比如{column_name: format string}(format string:"%Y:%m:%H:%M:%S")。
columns:要选取的列。一般没啥用,因为在sql命令里面一般就指定要选择的列了
chunksize:如果提供了一个整数值,那么就会返回一个generator,每次输出的行数就是提供的值的大小。

read_sql本质上是read_sql_table、read_sql_query的统一方式。

三者都return返回DataFrame。

  1. read_sql_table

Read SQL database table into a DataFrame.

  1. read_sql_query

Read SQL query into a DataFrame.

to_sql

参见pandas.to_sql函数,主要有以下几个参数:

  • name: 输出的表名
  • con: 与read_sql中相同
  • if_exits: 三个模式:fail,若表存在,则不输出;replace:若表存在,覆盖原来表里的数据;append:若表存在,将数据写到原表的后面。默认为fail
  • index:是否将df的index单独写到一列中
  • index_label:指定列作为df的index输出,此时index为True
  • chunksize: 同read_sql
  • dtype: 指定列的输出到数据库中的数据类型。字典形式储存:{column_name: sql_dtype}。常见的数据类型有sqlalchemy.types.INTEGER(), sqlalchemy.types.NVARCHAR(),sqlalchemy.Datetime()等,具体数据类型可以参考这里
    还是以写到mysql数据库为例:
df.to_sql(name='table', 
          con=con, 
          if_exists='append', 
          index=False,
          dtype={'col1':sqlalchemy.types.INTEGER(),
                 'col2':sqlalchemy.types.NVARCHAR(length=255),
                 'col_time':sqlalchemy.DateTime(),
                 'col_bool':sqlalchemy.types.Boolean
          })

注:如果不提供dtype,to_sql会自动根据df列的dtype选择默认的数据类型输出,比如字符型会以sqlalchemy.types.TEXT类型输出,相比NVARCHAR,TEXT类型的数据所占的空间更大,所以一般会指定输出为NVARCHAR;而如果df的列的类型为np.int64时,将会导致无法识别并转换成INTEGER型,需要事先转换成int类型(用map,apply函数可以方便的转换)。
https://www.cnblogs.com/arkenstone/p/6271923.html

插入数据

#插入方法无需改动,传入一个动态变化的字典
connect = pymysql.connect(host='',user='',db = '',password='',port=3306,charset='utf8')
cursor=connect.cursor()
data = {"id":'100','name':'Bob'}
table= 'stuinfo'
keys = ', '.join(data.keys())
values = ', '.join(['%s']*len(data))
sql = f"insert into {table}({keys}) values({values})"
try:
    cursor.execute(sql,tuple(data.values()))
    connect.commit()
    cursor.execute('select * from {table}'.format(table=table))
    print('执行成功',cursor.fetchall())
except:
    print("插入失败,数据回滚")
    connect.rollback()

更新数据

#更新,把Bon的age更新为28
sql = "update stuinfo set id=%s where name = %s"
cursor.execute(sql,("28",'Bob'))
connect.commit()
cursor.execute('select * from stuinfo')
print("Successful:",cursor.fetchall())

删除数据

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