我是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)
答案 0 :(得分:1)
快速而肮脏的答案:如果使用T-SQL,则在查询的开头放置SET NOCOUNT ON
行。
就像上面提到的@ Parfait,pandas read_sql
方法只能支持一个结果集。但是,当您在T-sql中生成临时表时,确实会以“((受影响的XX行))”的形式创建结果集,这将导致原始查询失败。通过设置NOCOUNT
,您可以消除所有早期回报,而只能从最终的SELECT
语句中获取结果。
或者,如果使用pyodbc光标而不是熊猫,则可以使用nextset()
从临时表中跳过结果集。有关pyodbc here的更多信息。