SQL 服务器温度 table 在 pyodbc 代码中不可用

SQL Server temp table not available in pyodbc code

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

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

我就这个直播问了一位同事,他的建议奏效了。所以我去更改了 testQuery 以创建一个全局温度 table 而不是本地温度(##Temp1 而不是 #Temp1)。然后去 sql 服务器测试临时文件 table 是否真的被创建了——它是。所以我发现问题出在第二个 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]

解决此问题的最佳方法是开始您的 SQL 查询:

"SET NOCOUNT ON"

这将输出所需的数据

即使这个问题有一个 "solution",即使用全局温度 table 而不是本地温度 table,未来的读者可能会受益于理解为什么问题发生在第一名.

当使用上述 table 的最后一个连接关闭时,临时 table 会自动删除。局部温度 table (#Temp1) 和全局温度 table (##Temp1) 的区别在于局部温度 table 仅对连接可见创建它的人,而现有的全局临时文件 table 可用于任何连接。

因此使用本地临时文件的以下代码 table 将失败 ...

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)

...而使用全局温度 table 的完全相同的代码将成功...

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 服务器的单独的第二个连接,而没有关闭第一个连接。

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

但是,第二个连接 可以 看到全局临时文件 table 因为第一个连接从未关闭,因此全局临时文件 table 继续存在.

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

SET NOCOUNT ON 对我有用。

执行方法() - JDBC Driver for SQL Server | Microsoft Docs

Return 值

  • true,如果语句returns一个结果集。
  • false,如果 returns 更新计数或没有结果。

如果您想要一个结果集,那么设置 SET NOCOUNT ON 就是您在语句中需要的设置。