如何获取 SQL 查询的元数据?

How to get metadata of an SQL query?

我知道如何使用 SQL Alchemy 读取现有数据库 table 的元数据:

meta = MetaData(bind=engine)
meta.reflect(schema="schema_name", views=True, resolve_fks=False)
res = meta.tables["table_name"]

问题:

如何获取 SQL 查询 (select * from tab1 join tab2 on tab1.id = tab2.id) 的元数据或列类型?

这有点 hack,但一种方法是使用查询创建临时 table,然后反映 table。 mssql 示例:

with engine.begin() as con:
    original_query = """\
    SELECT c.name as firstname, p.lastname 
    FROM parent p INNER JOIN child c
        ON c.parent_id = p.id
    """
    con.execute(
        sa.text(f"SELECT TOP 1 q.* INTO #tmp FROM ({original_query}) q")
    )
    con.commit()
    tmp = sa.Table("#tmp", sa.MetaData(), autoload_with=engine)
    for col in tmp.columns:
        print(repr(col))
    """console output:
    Column('firstname', NVARCHAR(length=100), table=<#tmp>, nullable=False)
    Column('lastname', VARCHAR(length=50, collation='SQL_Latin1_General_CP1_CI_AS'), table=<#tmp>)
    """

当您使用 sqlalchemy Core(不是 ORM)执行查询时,您将返回一个 ResultProxy 对象的实例。

ResultProxy 是底层 DBAPI 游标的包装器,如果您的代码使用的 RDBMS 驱动程序是按照 PEP 249 -- Python Database API Specification v2.0 or PEP 248 -- Python Database API Specification v1.0, you should be access the underlying ResultProxy.cursor object, which in turn should have .description 属性.

实现的

因此,类似于下面的代码应该可以正常工作:

res = session.execute(my_sql_statement)
columns = res.cursor.description
for col in columns:
    print(col.name, col.type_code, col.display_size, col.internal_size, col.precision, col.scale, col.null_ok)

对于像 SELECT "user".id AS user_id, "user".name AS user_name, "group".id AS group_id, "group".name AS group_name FROM "user" JOIN user_group AS user_group_1 ON "user".id = user_group_1.user_id JOIN "group" ON "group".id = user_group_1.group_id 这样的小查询,这是我看到的 PostgreSQL 数据库的输出:

user_id 23 None 4 None None None
user_name 1043 None 250 None None None
group_id 23 None 4 None None None
group_name 1043 None 250 None None None