【问题标题】:Retrieve postgres column types from psycopg2 cursor (or more efficienly map postgres oids to types)从 psycopg2 游标中检索 postgres 列类型(或更有效地将 postgres oid 映射到类型)
【发布时间】:2020-05-17 13:16:15
【问题描述】:

所以我正在编写一个脚本,它运行存储在文件中的一堆不同的 postgres sql 查询,并将结果(带有一些额外的计算)写回输出表。由于可以添加或更改查询以包含更多列,因此脚本将尝试更改输出表以包含相应的新列。

我知道我可以使用游标描述检索查询中列的 postgres oid,然后对 postgres 运行查询以将 oid 转换为 postgres 数据类型的字符串形式:

colnames = [desc[0] for desc in cur.description]
coloids = [desc[1] for desc in cur.description]
coltypes = [get_pg_type_from_oid(x) for x in coloids]
...
oid_catalog = {
    20:  'BIGINT',
    23 : 'INTEGER',
    1043: 'TEXT',
    1700: 'REAL',
}
def get_pg_type_from_oid(oid):
    if oid in oid_catalog:
        log.debug("converting oid type {} into {}".format(oid, oid_catalog[oid]))
        return oid_catalog[oid]
    q = "select {}::oid::regtype".format(oid)
    with conn, conn.cursor() as cur:
        cur.execute(q)
        newtype = cur.fetchone()[0]
        log.debug("converting oid type {} into {}".format(oid, newtype))
        oid_catalog[oid] = newtype
        return newtype

但是,我的 get_pg_type_from_oid 返回的数据类型字符串的格式似乎与我通常用于创建新表或添加列的格式不同(例如,“字符变化”而不是“VARCHAR(X)”等等)。

有没有更简单的方法来获取此映射?我已经开始手动将特定映射硬编码到我需要的存储的 oid_catalog 中,但我想要一个更通用、更优雅的解决方案。

与此相关,有什么方法可以使从 cursor.fetchall() 获取的结果以字符串形式表示自己,并具有直接包含到查询中的必要格式?

我目前正在手动执行此操作(请参见下面的代码),但我的直觉是必须有更好的方法。

def stringify(l):
    newl = []
    for x in l:
        if isinstance(x,float) or isinstance(x,Decimal):
            newl.append("{0:.2f}".format(round(float(x),2)))
        elif isinstance(x, datetime.datetime):
            newl.append("(TIMESTAMP '{}')".format(x.isoformat()))
        elif isinstance(x, datetime.date):
            newl.append("'{}'".format(str(x)))
        elif type(x) is str:
            newl.append("'"+x+"'")
        else:  # type(x) == 'int':
            #log.info("type else used for {}".format(x))
            newl.append(str(x))
    #log.debug("new string = {}".format(newl))
    return list(newl)

【问题讨论】:

    标签: python python-3.x postgresql psycopg2


    【解决方案1】:
    • character varying 是一个完全有效的类型:
    $ psql
    
    =# select pg_typeof(''::varchar);
         pg_typeof     
    -------------------
     character varying
    
    =# select 1::character varying(10);
     varchar 
    ---------
     1
    

    但是,您可以使用 oid 隐藏字段从 pg_type 表中获取其他名称(可能是规范名称)。

    =# select pg_typeof(''::varchar)::oid;
     pg_typeof 
    -----------
          1043
    
    =# select typname from pg_type where oid = pg_typeof(''::varchar)::oid;
     typname 
    ---------
     varchar
    

    【讨论】:

      猜你喜欢
      • 2023-03-20
      • 2016-04-15
      • 1970-01-01
      • 1970-01-01
      • 2010-09-26
      • 1970-01-01
      • 2021-04-20
      • 1970-01-01
      • 2014-11-02
      相关资源
      最近更新 更多