前面讨论了系列和SQL Server有关的话题,有兴趣可以看下,
前言
有朋友在 SQL Server 导入 Excel留言,说现实情况要复杂的多,没错,没有哪个方案是通吃的。况且我这里探讨的是思路,另外业务逻辑的处理可以放在数据导入之后,这个要具体问题具体分析了,如果需要,可以私下咨询我,我很乐意提供有偿服务:)
今天是填坑,写下Python的实现,思路其实很简单,要用到xldr库读取Excel(支持xls和xlsx),然后连接数据库,写入到数据库,有依赖不和不依赖pandas两种(今天放的是依赖pandas的实现),复杂的Excel仍然不在讨论之列。对复杂Excel的读取有兴趣的,建议看我另外一篇文章入门,使用Pandas读取复杂Excel表单。
下面代码,配合不同SQLAlchemy URL,可以实现多种数据库的导入,配合pandas则可以实现多种格式的导入和导出,另外在提高速度上也有很多优化空间,这里只是抛出一个最简陋的实现
代码原形
#require numpy pandas xlrd pymssql click sqlalchemyimport clickimport pandas as pdimport sysfrom sqlalchemy import create_engine"""pandas.read_excel(io, sheet_name=0, header=0, names=None, index_col=None,usecols=None, squeeze=False, dtype=None, engine=None, converters=None,true_values=None, false_values=None, skiprows=None, nrows=None, na_values=None,keep_default_na=True, verbose=False, parse_dates=False, date_parser=None,thousands=None, comment=None, skipfooter=0, convert_float=True,mangle_dupe_cols=True, **kwds)[source]"""@click.command()@click.option('--db', envvar='DATABASE_URI')@click.option('--sheet_name',default=0)@click.option('--if_exists', default='fail',prompt="fail, replace or append")@click.argument('table')@click.argument('excel_file', type=click.Path(exists=True))#mssql+pymssql://@127.0.0.1:1433/metabasedef main(db, sheet_name, if_exists, table, excel_file):try:engine= create_engine(db)if sheet_name:df=pd.read_excel(excel_file)else:df=pd.read_excel(excel_file,sheet_name=sheet_name)print(df.size)df.to_sql(table, con=engine, if_exists=if_exists,index=False)engine.dispose()except Exception as ex:print(ex)if __name__ == '__main__':main()
高速导入实现
先把DataFrame写到CSV
import tempfile#创建一个临时文件f=tempfile.mkstemp(suffix='.csv',dir='.')[1]#把DataFrame写到csv临时文件sep=","df.to_csv(tmpfile, na_rep='\\N', index=False,sep=sep)#有些数据库有schemeif schema_name is not None:table = f"{schema_name}.{table}"#必要的时候先建表df[:0].to_sql(table, engine, if_exists="replace", index=False)
MSSQL
#使用MS SQL Server的BULK INSERT命令实现高速导入sql_load = "BULK INSERT f{table_name} FROM '{tmpfile}';"engine.execute(sql_load)
MySQL
sql_load = f"""LOAD DATA LOCAL INFILE '{tmpfile}'INTO TABLE {table} FIELDS TERMINATEDBY '{sep}' LINES TERMINATEDBY '{newline}' IGNORE 1 LINES;"""engine.execute(sql_load)
PostgreSQL
sql_load = f"""COPY {table} FROM '{tmpfile}'DELIMITER '{sep}' CSV HEADER"""engine.execute(sql_load)
PostgreSQL还可以使用指针指针自带的copy_from命令,这样都不需要临时文件了。
cnn = engine.raw_connection()cursor = cnn.cursor()with io.StringIO() as fbuf:df.to_csv(fbuf, index=False, header=False, sep=sep)fbuf.seek(0)cursor.copy_from(fbuf, table, sep=sep, null='')cnn.commit()cursor.close()
之前有朋友说他的Excel导入后,金额都变成了字符串,导入后再转化都不行,我看了看,原来是千分位标示在作怪,其实pandas帮你想到了,它的thousands选项默认是None,你可以根据需要赋值(比如是逗号,也可能是点)。
这里把pandas.read_excel函数放这里,是想说明,如果我们的Excel比较复杂,我们完全可以制作一个配置文件,让我们的程序按配置文件的规则来读取Excel。
在ETL应用上,把Excel导入到数据库,实现方法有很多,适合你的才是最好的,
转CSV,然后导入(几乎每个数据库都有高速导入CSV的实现)
通过ODBC访问Excel
编程实现读取Excel,并写入数据库,目前C,Python,Java,PHP和Javascript都有比较成熟的库
Excel直接访问数据库,并写入数据库
最后再说一点,是否要把复杂的业务逻辑引入到数据库导入阶段,这个看你业务场景,ETL我们熟悉,但我觉得ELT更香(这个词都有些被公众号玩烂了吧)
最后的最后,我们还可以利用pyinstaller或者nuitka等打包工具,把这个打包成一个实用的小工具。
如果有什么建议和意见,也欢迎留言,或者加我个人微信,

谢谢点亮[在看]!




