通过 ODBC 将 pandas 输出连接到 Excel 工作表

Posted

技术标签:

【中文标题】通过 ODBC 将 pandas 输出连接到 Excel 工作表【英文标题】:Connect pandas output to excel sheet via ODBC 【发布时间】:2018-02-28 17:11:51 【问题描述】:

下面的查询执行以下操作:通过 ODBC 连接到 SQL Server 数据库,运行 SQL 脚本(许多查询由“;”分隔),为两个特定查询结果创建两个数据框,然后将它们导出到内部的两个选项卡一个 Excel 工作簿:

import pyodbc
import pandas as pd
import time

name= 'ouput' + str(time.strftime("%Y-%b-%d__%H_%M_%S",time.localtime()))
print ("Connecting via ODBC")

conn = pyodbc.connect('DSN=Server DB Prod', autocommit=True)

print ("Connected!\n")

inputdir = 'H:\\Queries\\ADS'

#for script in os.listdir(inputdir):
with open(inputdir+'\\' + 'query' +'.sql','r') as inserts:
    sqlScript = inserts.read()
    for statement in sqlScript.split(';'):
        with conn.cursor() as cur:
            cur.execute(statement)

query1="Select * from #leadership"
data1=pd.read_sql_query(query1, conn).sort_values(['channel','terr_code'], ascending=[0,1]).reset_index(drop=True)
#print(data1.head(n=100))
query2="Select * from #ml"
data2=pd.read_sql_query(query2, conn).sort_values(['channel','terr_code','client_name'], ascending=[0,1,1]).reset_index(drop=True)

print('query finished')
conn.close()

writer = pd.ExcelWriter(name+ '.xlsx')
data1.to_excel(writer,'Leadership Summary')
data2.to_excel(writer,'ML Detail')
writer.save()

print("Results were succesfully exported")

但是,我希望能够通过 ODBC 连接到现有的 excel 文件,以便动态更新我的工作簿的选项卡,并且不会丢失格式和图表 - 以实现真正的自动化。任何其他允许相同的解决方案肯定会起作用。

背景:我正在尝试自动化在 SQL Server 中运行查询(通过 Python)的过程,并让输出更新现有 excel 工作表的选项卡 - 我正在考虑通过 ODBC 连接。该工作表具有特定的格式,以及基于数据构建的公式+图表。

注意:我没有写权限,只有读权限,所以我无法通过 ODBC 将“最终”SQL 表连接到 excel。我正在从 Python 中的其他来源进行一些额外的数据混合(未显示),因此通过 ODBC 将 SQL 查询连接到 excel 将不起作用。

非常感谢任何帮助。

【问题讨论】:

【参考方案1】:

最好的策略是访问 Excel 工作簿并使用它的工具而不是外部工具来保持所有其他对象不变。因此,考虑win32com 客户端,您可以在其中访问Excel 对象库,例如其CopyFromRecordset 方法。

使用 Window 的 ADODB API 代替 pyodbc 作为数据库 API,它可以使用 ODBC 连接。此外,不需要pandas,因为工作表对象用于保存数据。注意:此解决方案仅适用于 Windows 机器。

import win32com.client as win32

try:
    # INITIALIZE OBJECTS
    xlapp = win32.gencache.EnsureDispatch('Excel.Application')
    ado_conn = win32.gencache.EnsureDispatch('ADODB.Connection')
    ado_rst = win32.gencache.EnsureDispatch('ADODB.Recordset')

    # OPEN CONNECTION
    ado_conn.Open('DSN=Server DB Prod')

    # RUN QUERIES
    with open(inputdir+'\\' + 'query' +'.sql','r') as inserts:
        sqlScript = inserts.read()
        for statement in sqlScript.split(';'):
            ado_conn.Execute(statement)

    # OPEN WORKBOOK AND UPDATE SHEETS
    xlwb = xlapp.Workbooks.Open(r'C:\Full\Path\To\Workbook.xlsx')

    ls = xlwb.Worksheets('Leadership Summary') 
    ls.Cells.ClearContents()
    ado_rst.Open("Select * from #leadership", ado_conn)
    for i in range(ado_rst.Fields.Count):
       ls.Cells(1, i+1).Value = ado_rst.Fields(i).Name     # COLUMNS
    ls.Range("A2").CopyFromRecordset(ado_rst)              # DATA ROWS
    ado_rst.Close()

    ml = xlwb.Worksheets('ML Detail')
    ml.Cells.ClearContents()
    ado_rst.Open("Select * from #ml", ado_conn)         
    for i in range(ado_rst.Fields.Count): 
       ml.Cells(1, i+1).Value = ado_rst.Fields(i).Name     # COLUMNS
    ml.Range("A2").CopyFromRecordset(ado_rst)              # DATA ROWS
    ado_rst.Close()

    ado_conn.Close()
    xlapp.Visible = True        # OPENS WORKBOOK WITH ABOVE CHANGES TO SCREEN

except Exception as e:
    print(e)

finally:
    # RELEASE RESOURCES
    ls = None; ml = None
    ado_rst = None; ado_conn = None
    xlwb = None; xlapp = None

希望这能揭穿任何认为 VBA(也是一种 COM 接口语言)是 Excel 唯一编码语言的人!

【讨论】:

我收到一个错误“'int' object is not callable”,但没有提及发生错误的行。这绝对不是 SQL 脚本,因为它按照我提供的版本运行得很好。有什么想法吗?此外,“希望这能揭穿任何认为 VBA(也是一种 COM 接口语言)是 Excel 唯一编码语言的人!”。这是什么魔法? 归结为列的编写方式。 .Count().Name() 不可调用,因此应将括号删除为 .Count.Name。见编辑。 你是对的 - 它运行成功。谢谢!。 2 个问题:#1 我将查询中的 A2 更改为 B8,这是数据开始写入的位置。但是,标题仍填充在第 1 行(A1 及以上)中。有没有办法不填充标题? #2 ClearContents 从选项卡中删除所有数据。但是,我想将数据保留在 1:7 行中,其中第 7 行是具有特定格式的标题。有什么方法可以指定我想保留/删除的内容吗?非常感谢! 在两个列循环中,如果您知道您的 Excel 对象将是 .Cells(7, 2) 对应于 B7,只需移动 .Cells(row, column)。所以循环.Cells(7, i+2).Value。并删除 ClearContents 行,但请注意,如果新的 shorter 查询替换它,之前的 longer 查询的最后几行可能会保留。 太棒了!而不是删除 ClearContents 我使用 ls.Range("B8:Z1000000").ClearContents() 来指定我想要清除的范围。有没有办法只写数据,没有列标题?对于这部杰作,这将是我最不需要的东西。 pywin32 功能绝对很酷

以上是关于通过 ODBC 将 pandas 输出连接到 Excel 工作表的主要内容,如果未能解决你的问题,请参考以下文章

在哪里下载 sun.jdbc.odbc.JdbcOdbcDriver(尝试将输出 csv 从 Spoon 连接到 SSMS)

无法通过 ODBC 将 Access 连接到 SQLlite

通过ODBC将Excel连接到PostgreSQL

通过 PDO ODBC 将 PHP 连接到 MSSQL

无法使用 MySQL 连接器/ODBC 将 Access DB 连接到 ODBC DSN

不使用 ODBC 将 Python 连接到 SQL Server