【问题标题】:Connect pandas output to excel sheet via ODBC通过 ODBC 将 pandas 输出连接到 Excel 工作表
【发布时间】: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 将不起作用。

非常感谢任何帮助。

【问题讨论】:

    标签: python python-2.7 python-3.x pandas


    【解决方案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 功能绝对很酷
    猜你喜欢
    • 2018-07-28
    • 1970-01-01
    • 2019-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-10
    • 2017-08-16
    • 2013-12-08
    相关资源
    最近更新 更多