pandas + pyodbc ODBC SQL 类型 -150 尚不支持
pandas + pyodbc ODBC SQL type -150 is not yet supported
我知道有很多关于此的主题,但我认为这是非常具体的。
我得到了用于审计目的的当前代码:
import pandas as pd
import pyodbc
query = """
--Top 50 high total CPU Queries
SELECT TOP 50
'High CPU Queries' as Type,
serverproperty('machinename') as 'Server Name',
isnull(serverproperty('instancename'),serverproperty('machinename')) as 'Instance Name',
COALESCE(DB_NAME(qt.dbid),
DB_NAME(CAST(pa.value as int)),
'Resource') AS DBNAME,
qs.execution_count as [Execution Count],
qs.total_worker_time/1000 as [Total CPU Time],
(qs.total_worker_time/1000)/qs.execution_count as [Avg CPU Time],
qs.total_elapsed_time/1000 as [Total Duration],
(qs.total_elapsed_time/1000)/qs.execution_count as [Avg Duration],
qs.total_physical_reads as [Total Physical Reads],
qs.total_physical_reads/qs.execution_count as [Avg Physical Reads],
qs.total_logical_reads as [Total Logical Reads],
qs.total_logical_reads/qs.execution_count as [Avg Logical Reads],
SUBSTRING(qt.text,qs.statement_start_offset/2,
(case when qs.statement_end_offset = -1
then len(convert(nvarchar(max), qt.text)) * 2
else qs.statement_end_offset end -qs.statement_start_offset)/2)
as query_text
FROM sys.dm_exec_query_stats qs
cross apply sys.dm_exec_sql_text(qs.sql_handle) as qt
outer apply sys.dm_exec_query_plan (qs.plan_handle) qp
outer APPLY sys.dm_exec_plan_attributes(qs.plan_handle) pa
where attribute = 'dbid'
ORDER BY
[Total CPU Time] DESC
"""
cnxn = pyodbc.connect('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
cnxn.execute(query).fetchall()
cnxn.close()
我收到以下错误:
cnxn.execute(sql_status_20).fetchall()
Traceback (most recent call last):
File "", line 1, in
pyodbc.ProgrammingError: ('ODBC SQL type -150 is not yet supported. column-index=1 type=-150', 'HY106')
谁能帮我处理一下?许多使用日期的 SQL 服务器审核脚本都存在同样的问题,我无法更改驱动程序,因为我的生产环境中有各种 SQL 版本。
如果您无法更改驱动程序,则需要将查询更改为它支持的 return 数据类型。
SQL 类型 -150 是 SQL_VARIANT
,由 SERVERPROPERTY
编辑 return。解决方法是将列显式 CAST
为受支持的类型,例如 nvarchar
:
CAST(SERVERPROPERTY('machinename') AS nvarchar(100)) AS 'Server Name',
CAST(ISNULL(SERVERPROPERTY('instancename'),SERVERPROPERTY('machinename')) AS nvarchar(100)) AS 'Instance Name',
如果很难将现有查询更改为显式 CAST 或 CONVERT 麻烦的值,那么您可以考虑尝试使用 pyodbc Output Converter Function。它使您能够定义一个 Python 函数,该函数将应用于为给定 ODBC SQL 类型返回的原始字节。
例如,此测试代码因您描述的错误而失败:
import pyodbc
cnxn = pyodbc.connect('DSN=SQLmyDb', autocommit=True)
crsr = cnxn.cursor()
server_name = crsr.execute("SELECT SERVERPROPERTY('machinename')").fetchval()
print(server_name)
crsr.close()
cnxn.close()
但这对我来说在 Python3
下工作正常
import pyodbc
def handle_sql_variant_as_string(value):
return value.decode('utf-16le')
cnxn = pyodbc.connect('DSN=SQLmyDb', autocommit=True)
crsr = cnxn.cursor()
cnxn.add_output_converter(-150, handle_sql_variant_as_string)
server_name = crsr.execute("SELECT SERVERPROPERTY('machinename')").fetchval()
print(server_name)
crsr.close()
cnxn.close()
我知道有很多关于此的主题,但我认为这是非常具体的。 我得到了用于审计目的的当前代码:
import pandas as pd
import pyodbc
query = """
--Top 50 high total CPU Queries
SELECT TOP 50
'High CPU Queries' as Type,
serverproperty('machinename') as 'Server Name',
isnull(serverproperty('instancename'),serverproperty('machinename')) as 'Instance Name',
COALESCE(DB_NAME(qt.dbid),
DB_NAME(CAST(pa.value as int)),
'Resource') AS DBNAME,
qs.execution_count as [Execution Count],
qs.total_worker_time/1000 as [Total CPU Time],
(qs.total_worker_time/1000)/qs.execution_count as [Avg CPU Time],
qs.total_elapsed_time/1000 as [Total Duration],
(qs.total_elapsed_time/1000)/qs.execution_count as [Avg Duration],
qs.total_physical_reads as [Total Physical Reads],
qs.total_physical_reads/qs.execution_count as [Avg Physical Reads],
qs.total_logical_reads as [Total Logical Reads],
qs.total_logical_reads/qs.execution_count as [Avg Logical Reads],
SUBSTRING(qt.text,qs.statement_start_offset/2,
(case when qs.statement_end_offset = -1
then len(convert(nvarchar(max), qt.text)) * 2
else qs.statement_end_offset end -qs.statement_start_offset)/2)
as query_text
FROM sys.dm_exec_query_stats qs
cross apply sys.dm_exec_sql_text(qs.sql_handle) as qt
outer apply sys.dm_exec_query_plan (qs.plan_handle) qp
outer APPLY sys.dm_exec_plan_attributes(qs.plan_handle) pa
where attribute = 'dbid'
ORDER BY
[Total CPU Time] DESC
"""
cnxn = pyodbc.connect('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
cnxn.execute(query).fetchall()
cnxn.close()
我收到以下错误:
cnxn.execute(sql_status_20).fetchall() Traceback (most recent call last): File "", line 1, in pyodbc.ProgrammingError: ('ODBC SQL type -150 is not yet supported. column-index=1 type=-150', 'HY106')
谁能帮我处理一下?许多使用日期的 SQL 服务器审核脚本都存在同样的问题,我无法更改驱动程序,因为我的生产环境中有各种 SQL 版本。
如果您无法更改驱动程序,则需要将查询更改为它支持的 return 数据类型。
SQL 类型 -150 是 SQL_VARIANT
,由 SERVERPROPERTY
编辑 return。解决方法是将列显式 CAST
为受支持的类型,例如 nvarchar
:
CAST(SERVERPROPERTY('machinename') AS nvarchar(100)) AS 'Server Name',
CAST(ISNULL(SERVERPROPERTY('instancename'),SERVERPROPERTY('machinename')) AS nvarchar(100)) AS 'Instance Name',
如果很难将现有查询更改为显式 CAST 或 CONVERT 麻烦的值,那么您可以考虑尝试使用 pyodbc Output Converter Function。它使您能够定义一个 Python 函数,该函数将应用于为给定 ODBC SQL 类型返回的原始字节。
例如,此测试代码因您描述的错误而失败:
import pyodbc
cnxn = pyodbc.connect('DSN=SQLmyDb', autocommit=True)
crsr = cnxn.cursor()
server_name = crsr.execute("SELECT SERVERPROPERTY('machinename')").fetchval()
print(server_name)
crsr.close()
cnxn.close()
但这对我来说在 Python3
下工作正常import pyodbc
def handle_sql_variant_as_string(value):
return value.decode('utf-16le')
cnxn = pyodbc.connect('DSN=SQLmyDb', autocommit=True)
crsr = cnxn.cursor()
cnxn.add_output_converter(-150, handle_sql_variant_as_string)
server_name = crsr.execute("SELECT SERVERPROPERTY('machinename')").fetchval()
print(server_name)
crsr.close()
cnxn.close()