python链接不同数据库会使用到不同的第三方库,SQLAlchemy可以很好的整合大部分常用数据库,利用SQLAlchemy可以很好的完成自用的数据库链接模块。因python中数据存储常用到DataFrame,所以在查询中增加了统一DataFrame格式输出,方便后续的操作。
因为工作原因,目前只完成了Oracle、MySQL、sqlserver、postgre四种数据库的查询部分,后续会陆续完善其余部分的相关操作。
# 更新时间:2022-01-20
import pandas as pd
from sqlalchemy import create_engine
from urllib import parse
import common.save_log as sl
'''
select 查询
insert 单条新增
update 修改
truncate 清空
connect 数据库连通性测验
insert_table 全表插入
'''
SQL_TYPE = ['select', 'insert', 'update', 'truncate', 'connect', 'insert_table']
def conn_oracle(database, sql_type, sql, like_str=None, data=None, table=None, schema=None):
if sql_type not in SQL_TYPE:
result = 'sql_type值不符合规定'
return result
else:
if 'service_name' in database.keys():
engine = create_engine(
'oracle+cx_oracle://%s:%s@%s:%s/?service_name=%s' % (
database['username'], parse.quote(database['password']), database['ip'], database['port'],
database['service_name']))
else:
engine = create_engine(
'oracle+cx_oracle://%s:%s@%s:%s/%s' % (
database['username'], parse.quote(database['password']), database['ip'], database['port'],
database['sid']))
conn = engine.connect()
if sql_type == 'select':
if like_str is not None:
data = conn.execute(sql, like_str)
else:
data = conn.execute(sql)
df_data = __select_data_to_df(data)
elif sql_type == 'insert':
conn.execute(sql)
df_data = 0
elif sql_type == 'update':
conn.execute(sql)
df_data = 0
elif sql_type == 'truncate':
conn.execute(sql)
df_data = 0
elif sql_type == 'insert_table':
pd.io.sql.to_sql(data, table, engine, index=False, schema=schema, if_exists='append')
df_data = 0
conn.close()
return df_data
def conn_mysql(database, sql_type, sql, like_str=None):
if sql_type not in SQL_TYPE:
result = 'sql_type值不符合规定'
return result
else:
engine = create_engine(
'mysql+pymysql://%s:%s@%s:%s/%s' % (
database['username'], parse.quote(database['password']), database['ip'], database['port'],
database['db_name']))
is_connect = False
for i in range(2):
try:
conn = engine.connect()
is_connect = True
if sql_type == 'connect':
return True
except BaseException as e:
sl.put_log_txt(e, '数据库链接')
continue
if is_connect:
if sql_type == 'select':
if like_str is not None:
data = conn.execute(sql, like_str)
else:
data = conn.execute(sql)
df_data = __select_data_to_df(data)
elif sql_type == 'insert':
df_data = conn.execute(sql)
elif sql_type == 'update':
df_data = conn.execute(sql)
conn.close()
else:
return False
return df_data
def conn_sqlserver(database, sql_type, sql, like_str=None):
if sql_type not in SQL_TYPE:
result = 'sql_type值不符合规定'
return result
else:
username = database['username']
pwd = parse.quote(database['password'])
ip = database['ip']
db_name = database['db_name']
engine = create_engine('mssql+pyodbc://%s:%s@%s/%s?driver=ODBC+Driver+17+for+SQL+Server' % (username, pwd, ip, db_name))# ODBC的版本要和运行环境安装的版本一致
is_connect = False
for i in range(2):
try:
conn = engine.connect()
is_connect = True
if sql_type == 'connect':
return True
except BaseException as e:
sl.put_log_txt(e, '数据库链接')
continue
if is_connect:
if sql_type == 'select':
if like_str is not None:
data = conn.execute(sql, like_str)
else:
data = conn.execute(sql)
df_data = __select_data_to_df(data)
elif sql_type == 'insert':
df_data = conn.execute(sql)
elif sql_type == 'update':
df_data = conn.execute(sql)
conn.close()
else:
return False
return df_data
def conn_postgre(database, sql_type, sql, like_str=None):
if sql_type not in SQL_TYPE:
result = 'sql_type值不符合规定'
return result
else:
username = database['username']
pwd = parse.quote(database['password'])
ip = database['ip']
if 'port' in database:
port = ':%s' % database['port']
else:
port = ''
db_name = database['db_name']
if 'charset' in database:
charset = '?charset=%s' % database['charset']
else:
charset = ''
engine = create_engine('postgresql+psycopg2://%s:%s@%s%s/%s%s' % (username, pwd, ip, port, db_name, charset))
conn = engine.connect()
if sql_type == 'select':
if like_str is not None:
data = conn.execute(sql, like_str)
else:
data = conn.execute(sql)
df_data = __select_data_to_df(data)
elif sql_type == 'insert':
df_data = conn.execute(sql)
elif sql_type == 'update':
df_data = conn.execute(sql)
conn.close()
return df_data
def __select_data_to_df(data):
'''
函数内容:数据库select所得数据转存为DataFrame
参数:data 数据库select所得数据
返回值:df_data DataFrame格式的数据库select数据,包含列名(数据库中对应列名)
'''
list_data = []
list_column = [i[0] for i in data.cursor.description]
for item in data:
list_data.append(item)
df_data = pd.DataFrame(data=list_data, columns=list_column)
return df_data
第三方库的导入问题
除了py文件中明确import的第三方库,不同数据库还需要各自的第三方库:
oracle==>cx_Oracle
mysql==>PyMySQL
sqlserver==>pyodbc
postgre==>psycopg2
数据库连接问题
1、密码中若有特殊符号,例如@时,若直接传参,会令程序识别出错,需要转义传参,如下:
engine = create_engine( 'mysql+pymysql://%s:%s@%s:%s/%s' % (
database['username'], parse.quote(database['password']), database['ip'],database['port'],database['db_name']))
2、sql server来连接器有多种,在尝试了pymssql和pyodbc后,选择了pyodbc,好处是能够避免读写时中文乱码问题。但需注意运行环境需要安装odbc的驱动。
驱动下载地址:https://docs.microsoft.com/zh-cn/sql/connect/odbc/download-odbc-driver-for-sql-server?view=sql-server-ver15sql执行问题
1、select语句执行like时,会用到%,但在python中会将其认为传参字符,需特殊处理,链接代码见conn_mysql函数部分,传参方式如下
like_str= ['%%%s%%' % string]
sql = "SELECT id FROM table where column like %s"
data = conn_database.conn_mysql(OA_DATABASE_DETAIL, 'select', sql,like_str=like_str)
2、sql值中含有单引号时,sql会错误识别,导致执行失败,若要带单引号,需将单引号转化为两个单引号,但转化时要注意,不能整个sql做替换,要在值中做替换。示例如下:
s = "a'b"
sql = "select * from table_name where name='%s'" %s
# 正确替换
s = s.replace("'","''")
# 错误替换
sql = sql.replace("'","''")
最后
该代码是自用,适用场景有限,代码格式也不算太标准,若有任何建议欢迎反馈。