2016-06-16 15 views
4

Ich führe eine Reihe von komplexen SQL-Abfragen in Python und es betrifft temporäre Tabellen. Meine automatische Commit-Methode scheint nicht zu funktionieren, um die Daten aus der temporären Tabelle abzurufen. Der Code-Snippet Ich verwende unten und dies ist die Ausgabe erhalte ich:SQL Server temporäre Tabelle nicht verfügbar in pyodbc Code

testQuery=""" 
    Select top 10 * 
    INTO #Temp1 
    FROM Table1 t1 
    JOIN Table2 t2 
    on t1.key=t2.key 
""" 
    cnxn=pyodbc.connect(r'DRIVER={SQL Server Native Client 11.0};SERVER=server;DATABASE=DB;UID=UID;PWD=PWD') 
    cnxn.autocommit=True 
    cursor=cnxn.cursor() 
    cursor.execute(testQuery) 
    cursor.execute("""Select top 10 * from #Temp1""") 
    <pyodbc.Cursor at 0x8f78930> 


cnxn=pyodbc.connect(r'DRIVER={SQL Server Native Client 11.0};SERVER=server;DATABASE=DB;UID=UID;PWD=PWD') 
cnxn.autocommit=True 
cursor=cnxn.cursor() 
cursor.execute(testQuery) 
cursor.execute("""Select top 10 * from #Temp1""") 

Antwort

2

Auch wenn diese Frage eine "Lösung" hat, dh eine globale temporäre Tabelle anstelle einer lokalen temporären Tabelle verwendet, könnten zukünftige Leser davon profitieren, zu verstehen, warum das Problem überhaupt aufgetreten ist.

Eine temporäre Tabelle wird automatisch gelöscht, wenn die letzte Verbindung, die diese Tabelle verwendet, geschlossen wird. Der Unterschied zwischen einer lokalen temporären Tabelle (#Temp1) und einer globalen temporären Tabelle (##Temp1) besteht darin, dass die lokale temporäre Tabelle nur für die Verbindung sichtbar ist, die sie erstellt hat, während eine vorhandene globale temporäre Tabelle für jede Verbindung verfügbar ist.

So ist der folgende Code eine lokale temporäre Tabelle verwendet, wird fehlschlagen ...

conn = pyodbc.connect(conn_str, autocommit=True) 
crsr = conn.cursor() 

sql = """\ 
SELECT 1 AS foo, 2 AS bar INTO #Temp1 
""" 
crsr.execute(sql) 

conn = pyodbc.connect(conn_str, autocommit=True) 
crsr = conn.cursor() 

sql = """\ 
SELECT foo, bar FROM #Temp1 
""" 
crsr.execute(sql) 
row = crsr.fetchone() 
print(row) 

... während die exakt gleichen Code eine globale temporäre Tabelle mit gelingen wird ...

conn = pyodbc.connect(conn_str, autocommit=True) 
crsr = conn.cursor() 

sql = """\ 
SELECT 1 AS foo, 2 AS bar INTO ##Temp1 
""" 
crsr.execute(sql) 

conn = pyodbc.connect(conn_str, autocommit=True) 
crsr = conn.cursor() 

sql = """\ 
SELECT foo, bar FROM ##Temp1 
""" 
crsr.execute(sql) 
row = crsr.fetchone() 
print(row) 

... weil der zweite Aufruf pyodbc.connect eine separate zweite Verbindung zum SQL Server öffnet, ohne den ersten zu schließen.

Die zweite Verbindung kann die lokale temporäre Tabelle, die von der ersten Verbindung erstellt wird, nicht sehen. Beachten Sie, dass die lokale temporäre Tabelle weiterhin vorhanden ist, da die erste Verbindung nie geschlossen wurde, die zweite Verbindung jedoch nicht.

Die zweite Verbindung kann jedoch die globale temporäre Tabelle anzeigen, da die erste Verbindung nie geschlossen wurde und daher die globale temporäre Tabelle weiterhin vorhanden ist.

Dieser Verhaltenstyp hat Auswirkungen auf ORMs und andere Mechanismen, die Verbindungen zu dem Server für jede SQL-Anweisung, die er ausführt, implizit öffnen und schließen können.

1

fragte ich einen Kollegen über dieses Leben und seine Vorschläge gearbeitet. Also ging ich und änderte testQuery, um eine globale temporäre Tabelle anstelle einer lokalen zu erstellen (## Temp1 anstelle von # Temp1). Und ging zu SQL-Server, um zu testen, ob die temporäre Tabelle tatsächlich erstellt wurde - es war. So isolierte ich, dass das Problem die zweite cursor.execute -Anweisung war. Ich änderte den Code, um stattdessen pandas read_sql_query zu verwenden, und alles hat funktioniert! Unten ist der Code, den ich verwendet:

testQuery=""" 
    Select top 10 * 
    INTO ##Temp1 
    FROM Table1 t1 
    JOIN Table2 t2 
    on t1.key=t2.key 
""" 
    cnxn=pyodbc.connect(r'DRIVER={SQL Server Native Client 11.0};SERVER=server;DATABASE=DB;UID=UID;PWD=PWD') 
    cnxn.autocommit=True 
    cursor=cnxn.cursor() 
    cursor.execute(testQuery) 
    cnxn.commit() 
    query1="Select top 10 * from ##Temp1" 
    data1=pd.read_sql_query(query1, cnxn) 
    data1[:10] 
+0

Haben Sie auch herausgefunden, warum globale temporäre Tabellen funktionieren, während lokale nicht funktionieren? Ich hatte auch ein ähnliches Problem, wo ich mehrere temporäre Tabellen erstellen musste. Die erste Temp-Tabelle funktionierte, die nachfolgenden jedoch nicht. Die Verwendung der Methode zum Erstellen von globalen temporären Tabellen hat sich bewährt – Alex

0

Der beste Weg, um dies zu realisieren ist Ihre SQL-Abfrage starten mit:

"SET NOCOUNT ON"

Dies wird Ausgang

die gewünschten Daten
Verwandte Themen