【问题标题】:SQLAlchemy accessing column types from query resultsSQLAlchemy 从查询结果中访问列类型
【发布时间】:2021-02-21 23:29:14
【问题描述】:

我正在使用 SQLAlchemy(使用 pymssql 驱动程序)连接到 SQL Server 数据库。

import sqlalchemy

conn_string = f'mssql+pymssql://{uid}:{pwd}@{instance}/?database={db};charset=utf8'
sql = 'SELECT * FROM FAKETABLE;'

engine = sqlalchemy.create_engine(conn_string)
connection = engine.connect()
result = connection.execute(sql)
result.cursor.description

导致:

(('col_1', 1, None, None, None, None, None),
 ('col_2', 1, None, None, None, None, None),
 ('col_3', 4, None, None, None, None, None),
 ('col_4', 3, None, None, None, None, None),
 ('col_5', 3, None, None, None, None, None))

根据PEP 249(光标的.description属性):

前两项(name 和 type_code)是必填项,其他五项是可选的,如果无法提供有意义的值,则设置为 None。

我假设整数 (1, 1, 4, 3, 3) 是列类型。

我的两个问题:

  1. 如何将这些整数映射到数据类型(如 char、integer 等)?
  2. 这些是 SQL 数据类型吗?如果没有,是否可以获取 SQL 数据类型?

FWIW,当我使用 raw_connection() 而不是 connect() 时,我得到了相同的结果。

遇到了三个类似的问题(不回答这个特定问题)。我需要使用connect() + execute() 方法。

【问题讨论】:

    标签: python sql-server sqlalchemy pymssql


    【解决方案1】:

    如果没有,是否可以获取 SQL 数据类型?

    SQL Server 函数 sys.dm_exec_describe_first_result_set 可用于直接获取 SQL 列的数据类型以进行提供的查询:

    SELECT column_ordinal, name, system_type_name, *
    FROM sys.dm_exec_describe_first_result_set('here goes query', NULL, 0) ; 
    

    在你的例子中:

    sql = """SELECT column_ordinal, name, system_type_name 
        FROM sys.dm_exec_describe_first_result_set('SELECT * FROM FAKETABLE', NULL, 0) ;"""
    

    为:

    CREATE TABLE FAKETABLE(id INT, d DATE, country NVARCHAR(10));
    
    SELECT column_ordinal, name, system_type_name 
    FROM sys.dm_exec_describe_first_result_set('SELECT * FROM FAKETABLE', NULL, 0) ;
    
    +-----------------+----------+------------------+
    | column_ordinal  |  name    | system_type_name |
    +-----------------+----------+------------------+
    |              1  | id       | int              |
    |              2  | d        | date             |
    |              3  | country  | nvarchar(10)     |
    +-----------------+----------+------------------+
    

    db<>fiddle demo

    【讨论】:

    • 谢谢,我希望答案可以在元数据中的某个地方找到,但这是我所拥有的最好的。
    【解决方案2】:

    PEP249type_code通过不同的DB类型看起来并不相同。

    所以这个答案将集中在 MS SQL Server 上。

    1. 如何将这些整数映射到数据类型(如 char、integer 等)?

    您可以使用以下代码创建 type_codetype_object 的字典:

    import inspect
    import pymssql
    
    code_map = {
        type_obj.value: (type_name, type_obj)
        for type_name, type_obj
        in inspect.getmembers(
            pymssql,
            predicate=lambda x: isinstance(x, pymssql.DBAPIType),
        )
    }
    

    这将产生以下字典:

    {2: ('BINARY', <DBAPIType 2>),
     4: ('DATETIME', <DBAPIType 4>),
     5: ('DECIMAL', <DBAPIType 5>),
     3: ('NUMBER', <DBAPIType 3>),
     1: ('STRING', <DBAPIType 1>)}
    

    很遗憾,我无法访问正在运行的 MS SQL Server 实例。所以我无法检查类型结果是否与您的示例匹配。

    1. 这些是 SQL 数据类型吗?如果没有,是否可以获取 SQL 数据类型?

    查看 PEP 和此结果:此字段不是 SQL 数据类型。这是“类型对象”。

    DB API 似乎不提供检查查询结果元数据的方法/函数。 API 只是提供了一种将数据类型从 SQL 绑定到 python 类型的方法。

    如果您需要获取准确的 SQL 数据类型,则必须编写特定于服务器的 SQL 查询。

    【讨论】:

    • 谢谢,但是看起来这只是从代码到数据类型的映射。我对 SQL 数据类型特别感兴趣。
    【解决方案3】:

    可能是驱动程序本身。下面我的代码几乎和你的一样,只是使用 AdventureWorks 上的 pyodbc 驱动程序。我选择了一张包含许多不同数据类型的表格,它们都显示出来了。

    import sqlalchemy
    conn_string = conn_string = f'mssql+pyodbc://{username}:{pwd}@{instance}/AdventureWorksLT2017?driver=ODBC+Driver+17+for+SQL+Server'
    sql = 'SELECT TOP 10 * FROM SalesLT.Product;'
    
    engine = sqlalchemy.create_engine(conn_string)
    connection = engine.connect()
    
    result = connection.execute(sql)
    print(result.cursor.description)
    

    输出:

    (('ProductID', <class 'int'>, None, 10, 10, 0, False), ('Name', <class 'str'>, None, 50, 50, 0, False), ('ProductNumber', <class 'str'>, None, 25, 25, 0, False), ('Color', <class 'str'>, None, 15, 15, 0, True), ('StandardCost', <class 'decimal.Decimal'>, None, 19, 19, 4, False), ('ListPrice', <class 'decimal.Decimal'>, None, 19, 19, 4, False), ('Size', <class 'str'>, None, 5, 5, 0, True), ('Weight', <class 'decimal.Decimal'>, None, 8, 8, 2, True), ('ProductCategoryID', <class 'int'>, None, 10, 10, 0, True), ('ProductModelID', <class 'int'>, None, 10, 10, 0, True), ('SellStartDate', <class 'datetime.datetime'>, None, 23, 23, 3, False), ('SellEndDate', <class 'datetime.datetime'>, None, 23, 23, 3, True), ('DiscontinuedDate', <class 'datetime.datetime'>, None, 23, 23, 3, True), ('ThumbNailPhoto', <class 'bytearray'>, None, 0, 0, 0, True), ('ThumbnailPhotoFileName', <class 'str'>, None, 50, 50, 0, True), ('rowguid', <class 'str'>, None, 36, 36, 0, False), ('ModifiedDate', <class 'datetime.datetime'>, None, 23, 23, 3, False))
    

    您可以试试这个驱动程序作为比较吗?

    【讨论】:

    • 谢谢,这很有帮助。但我需要使用pymssql
    猜你喜欢
    • 2019-08-17
    • 2016-07-02
    • 1970-01-01
    • 1970-01-01
    • 2018-08-30
    • 2018-03-04
    • 1970-01-01
    • 1970-01-01
    • 2017-09-09
    相关资源
    最近更新 更多