【问题标题】:How do I select a PostgreSQL system column using SQLAlchemy?如何使用 SQLAlchemy 选择 PostgreSQL 系统列?
【发布时间】:2020-04-22 01:14:38
【问题描述】:

Postgresql 在每个表上隐式定义了几列,例如xmaxctid(参见docs)。

假设我的 SQLALchemy 表定义没有指定这些列,有没有办法使用核心 sql 功能(即不是 SA 的 ORM 部分)来选择它们?

由于xmax 未在表定义中明确定义,因此以下内容不起作用。

table = sa.Table(
    "mytable",
    metadata,
    sa.Column("col_a", sa.BIGINT),
    sa.Column("date", sa.DATE),
)

s = sa.select([table.c.xmax])
result = engine.execute(s)

具体来说,我的要求是在 upsert 的 returning 子句中引用 xmax

insert(mytable).returning((mytable.c.xmax == 0).label("inserted"))

【问题讨论】:

  • 我现在记得我可以提供文字 sql 作为字符串并回避问题,尽管我对任何其他方法感兴趣。 insert(mytable).returning(sa.text("xmax = 0 AS inserted"))

标签: sql postgresql sqlalchemy


【解决方案1】:

如果您不想更改现有的表声明,可以使用sqlalchemy.column() 函数(注意column 中的小写c):

xmax = sa.column('xmax')
sa.insert(mytable).returning((xmax == 0).label("inserted"))

但是,如果您的 SQL 语句从多个表中进行选择(例如,在连接中),那么 PostgreSQL 会抱怨它不知道您在谈论哪个 xmax 列:

ProgrammingError: (psycopg2.ProgrammingError) column "xmax" does not exist

在这种情况下,您可以使用(遗憾的是未记录)_selectable 参数:

xmax = sa.column('xmax', _selectable=mytable)
sa.insert(mytable).returning((xmax == 0).label("inserted"))

这在连接表查询中和仅从一个表中选择的情况下一样有效,因此您可以随时使用它。

【讨论】:

    【解决方案2】:

    一种选择是在 SA 表定义中将 xmax 声明为系统列:

    table = sa.Table(
        # ...,
        sa.Column("xmax", sa.TEXT, system=True),
    )
    

    这将允许您像访问任何其他列一样访问table.c.xmax(因此您建议的table.c.xmax == 0 应该可以工作)。 system=True 标志告诉 SA 在发出 CREATE TABLE 时不要尝试显式创建 xmax 列。

    (我在这里使用了sa.TEXT 作为一种解决方法,因为sqlalchemy.dialects.postgresql 不提供XID 数据类型,显然xid 不能转换为数字类型。)

    【讨论】:

    • 谢谢,这是一个有趣的答案。我不知道列上的系统标志
    猜你喜欢
    • 2012-12-08
    • 2016-09-05
    • 2021-05-15
    • 1970-01-01
    • 1970-01-01
    • 2014-06-09
    • 2015-09-04
    • 2021-11-07
    • 2021-08-01
    相关资源
    最近更新 更多