暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

使用Python导入Excel到SQL Server数据库

alitrack 2021-04-02
2087

前面讨论了系列和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 sqlalchemy
    import click
    import pandas as pd
    import sys
    from 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/metabase


    def 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)


      #有些数据库有scheme
      if 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 TERMINATED
          BY '{sep}' LINES TERMINATED
          BY '{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等打包工具,把这个打包成一个实用的小工具。


              如果有什么建议和意见,也欢迎留言,或者加我个人微信,



              谢谢点亮[看]




              文章转载自alitrack,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

              评论