2014-10-01 54 views
4

考慮:讀取存儲過程的選擇結果爲大熊貓數據幀

CREATE PROCEDURE my_procedure 
    @Param INT 
AS 
    SELECT Col1, Col2 
    FROM Table 
    WHERE Col2 = @Param 

我希望能夠以此爲:

import pandas as pd 
import pyodbc 

query = 'EXEC my_procedure @Param = {0}'.format(my_param) 
conn = pyodbc.connect(my_connection_string) 

df = pd.read_sql(query, conn) 

但是,這將引發一個錯誤:

ValueError: Reading a table with read_sql is not supported for a DBAPI2 connection. Use an SQLAlchemy engine or specify an sql query 

SQLAlchemy也不起作用:

import sqlalchemy 
engine = sqlalchemy.create_engine(my_connection_string) 
df = pd.read_sql(query, engine) 

拋出:

ValueError: Could not init table 'my_procedure' 

我其實可以直接使用pyodbc執行語句:

cursor = conn.cursor() 
cursor.execute(query) 
results = cursor.fetchall() 
df = pd.DataFrame.from_records(results) 

有沒有辦法來直接將這些程序結果的數據幀?

+2

您使用的是什麼版本的熊貓?你可以嘗試使用'pd.read_sql_query'而不是'read_sql'嗎? ('read_sql'中存在一個關於執行存儲過程的錯誤) – joris 2014-10-01 08:06:06

回答

3

https://code.google.com/p/pyodbc/wiki/StoredProcedures

我不是一個Python的專家,但SQL Server有時返回語句執行計數。例如,更新將會告訴更新了多少行。

只需使用'SET NO COUNT;'在批次調用的前面。這將刪除插入,更新和刪除的計數。

確保您使用的是正確的本地客戶端模塊。

看看這個堆棧溢出的例子。

它有一個adhoc SQL和調用存儲過程的例子。

Calling a stored procedure python

好運

+0

'SET NOCOUNT ON'不幸在這種情況下不起作用。 – joeb1415 2014-10-01 16:58:08

+0

在我的存儲過程開始時添加SET NOCOUNT ON。謝謝。另外,我嘗試在查詢的開始處添加「SET NOCOUNT ON;」,這也起作用。 – FistOfFury 2017-03-13 14:48:32

1

使用ODBC語法調用存儲過程(與參數,而不是字符串格式化)適用於使用熊貓0.14.1和pyodbc 3.0.7裝載dataframes。以下示例使用AdventureWorks2008R2 sample database

先確認預期的結果使用pyodbc調用存儲過程:

import pandas as pd 
import pyodbc 
connection = pyodbc.connect(driver='{SQL Server Native Client 11.0}', server='ServerInstance', database='AdventureWorks2008R2', trusted_connection='yes') 
sql = "{call dbo.uspGetEmployeeManagers(?)}" 
params = (3,) 
cursor = connection.cursor() 
rows = cursor.execute(sql, params).fetchall() 
print(rows) 

應返回:

[(0, 3, 'Roberto', 'Tamburello', '/1/1/', 'Terri', 'Duffy'), (1, 2, 'Terri', 'Duffy', 
'/1/', 'Ken', 'Sánchez')] 

現在使用熊貓的結果加載到數據幀:

df = pd.read_sql(sql=sql, con=connection, params=params) 
print(df) 

應該返回:

RecursionLevel BusinessEntityID FirstName LastName OrganizationNode \ 
0    0     3 Roberto Tamburello   /1/1/ 
1    1     2  Terri  Duffy    /1/ 

    ManagerFirstName ManagerLastName 
0   Terri   Duffy 
1    Ken   Sánchez 

編輯

既然你不能更新到0.14大熊貓。1,從pyodbc使用pandas.DataFrame.from_records加載的結果:

# get column names from pyodbc results 
columns = [column[0] for column in cursor.description] 
df = pd.DataFrame.from_records(rows, columns=columns) 
+0

這在熊貓0.14.0中不起作用。我目前無法升級到0.14.1以在那裏測試,但感謝提示。 – joeb1415 2014-10-01 16:54:57

+0

@ joeb1415更新瞭如何在不使用'read_sql'的情況下填充數據框 – Bryan 2014-10-01 17:13:55

1

使用read_sql_query()代替。

看起來像@joris(+1)已經在評論中直接提到了這個問題,但我沒有看到它,因爲它不在答案部分。

使用SQLA引擎 - 除了SQLAlchemy,Pandas只支持SQLite。然後使用read_sql_query()而不是read_sql()。後者試圖自動檢測你是傳遞一個表名還是一個完整的查詢,但它看起來不像'EXEC'關鍵字那麼好。使用read_sql_query()會跳過自動檢測,並允許您明確指出您正在使用查詢(還有一個read_sql_table())。

import pandas as pd 
import sqlalchemy 

query = 'EXEC my_procedure @Param = {0}'.format(my_param) 
engine = sqlalchemy.create_engine(my_connection_string) 
df = pd.read_sql_query(query, engine)