Python使用临时表运行SQL查询

时间:2018-03-27 14:57:09

标签: python sql pandas

我是Python-SQL连接世界的新手。我的目标是通过我的python脚本执行长SQL查询,以pandas DataFrame格式从SQL检索数据。

我的大多数SQL查询都很长,在最后一个临时表的最终SELECT语句之前有多个临时表。当我在Python中运行这样一个单片查询时,我得到一个错误 -

  

" pandas.io.sql.DatabaseError:sql"

执行失败

虽然它们在MS SQL Management Studio中运行得非常好

我怀疑这是由于临时表,因为如果我将我的长查询分成两部分(第一部分中的最终SELECT之前的所有部分和第二部分中的最终SELECT )两节顺序,运行正常

有人可以指导我为什么这样或者可选择使用临时表/视图运行长查询并在pandas DataFrame中检索结果的最佳方法是什么?

这是我的示例Python代码,理想情况下应该使用一个好的名称作为输入并运行SQL来检索数据框中的结果,但是如果使用临时表进行查询则会失败

import pyodbc as db
import pandas as pd
filename = 'file.sql'
username = 'XXXX'
password = 'YYYYY'
driver= '{ODBC Driver 13 for SQL Server}' 
database = 'DB'
server = 'local'
conn = db.connect('DRIVER='+driver+'; PORT=1433; SERVER='+server+'; 
PORT=1443; DATABASE='+database+'; UID='+username+'; PWD='+ password)
fd = open(filename, 'r')
sqlfile = fd.read()
fd.close()

sqlcommand1 = sql
df_table = pd.read_sql(sqlcommand1, conn)

如果我将我的sql查询分成两部分(一部分包含所有临时表,第二部分包含最终Select),那么它运行正常。下面是一个修改过的函数,它在查找' / ** /'之后拆分长查询。它工作正常

"""
This Function Reads a SQL Script From an Extrenal File and Executes The 
Script in SQL. If The SQL Script Has Bunch of Tem Tables/Views
Followed By a Select Statement to Retrieve Data From Those Views Then Input 
SQL File Should Have '/**/' Immediately Before the Final
Select Statement. This is to Esnure Final Select Statement is Executed on 
the Temporary Views Already Run by Python. 
Input is a SQL File Name and Output is a DataFrame
"""

import pyodbc as db
import pandas as pd
filename = 'filename.sql'
username = 'XXXX'
password = 'YYYYY'
driver= '{ODBC Driver 13 for SQL Server}' 
database = 'DB'
server = 'local'
conn = db.connect('DRIVER='+driver+'; PORT=1433; SERVER='+server+'; 
PORT=1443; DATABASE='+database+'; UID='+username+'; PWD='+ password)
fd = open(filename, 'r')
sqlfile = fd.read()
fd.close()

sql = sqlfile.split('/**/')

sqlcommand1 = sql[0] #1st Section of Query with temp tables
sqlcommand2 = sql[1] #2nd section of Query with final SELECT statement
conn.execute(sqlcommand1)
df_table = pd.read_sql(sqlcommand2, conn)

1 个答案:

答案 0 :(得分:1)

快速而肮脏的答案:如果使用T-SQL,则在查询的开头放置SET NOCOUNT ON行。

就像上面提到的@ Parfait,pandas read_sql方法只能支持一个结果集。但是,当您在T-sql中生成临时表时,确实会以“((受影响的XX行))”的形式创建结果集,这将导致原始查询失败。通过设置NOCOUNT,您可以消除所有早期回报,而只能从最终的SELECT语句中获取结果。

或者,如果使用pyodbc光标而不是熊猫,则可以使用nextset()从临时表中跳过结果集。有关pyodbc here的更多信息。