SQL Server临时表在pyodbc代码中不可用

时间:2016-06-16 15:13:54

标签: python sql sql-server database-connection pyodbc

我在python中运行了一系列复杂的sql查询,它涉及临时表。我的自动提交方法似乎无法从临时表中检索数据。我在下面使用的代码片段,这是我得到的输出:

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""")

3 个答案:

答案 0 :(得分:5)

即使这个问题有一个&#34;解决方案&#34;,即使用全局临时表而不是本地临时表,未来的读者可能会从首先了解问题的原因中受益。

当关闭使用该表的最后一个连接时,将自动删除临时表。本地临时表(#Temp1)和全局临时表(##Temp1)之间的区别在于本地临时表仅对创建它的连接可见,而现有的全局临时表可用任何联系。

因此,使用本地临时表的以下代码将失败...

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)

...使用全局临时表的完全相同的代码将成功...

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)

...因为第二个pyodbc.connect调用会打开一个单独的第二个连接到SQL Server而不关闭第一个连接。

第二个连接无法看到第一个连接创建的本地临时表。请注意,本地临时表仍然存在,因为第一个连接从未关闭,但第二个连接无法看到它。

但是,第二个连接可以查看全局临时表,因为第一个连接从未关闭,因此全局临时表继续存在。

此类行为会影响ORM和其他机制,这些机制可能会为其执行的每个SQL语句隐式打开和关闭与服务器的连接。

答案 1 :(得分:2)

我问了一位同事关于这次的直播,他的建议也奏效了。所以我去改变testQuery来创建一个全局临时表而不是本地(## Temp1而不是#Temp1)。然后去sql server测试临时表是否真正被创建 - 它是。所以我发现问题是第二个cursor.execute语句。我修改了代码以使用pandas read_sql_query而且一切都解决了!以下是我使用的代码:

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]

答案 2 :(得分:0)

最好的解决方法是使用以下命令启动SQL查询:

“SET NOCOUNT ON”

这将输出所需的数据