如何使用SQLAlchemy选择PostgreSQL系统列?

huangapple go评论62阅读模式
英文:

How do I select a PostgreSQL system column using SQLAlchemy?

问题

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

假设我的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"))
英文:

Postgresql implicitly defines several columns on every table, such as xmax and ctid (see docs).

Assuming my SQLALchemy table definition does not specify these columns, is there a way to select them using the core sql functionality (i.e. not the ORM part of SA)?

The following does not work as xmax is not explicitly defined in the table definition.

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)

Specifically my requirement is to reference xmax in the returning clause of an upsert.

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

答案1

得分: 5

如果您不想更改现有的表声明,您可以使用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"))

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

英文:

If you don't want to change your existing table declarations, you can use the sqlalchemy.column() function (note the lowercase c in column):

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

However, if your SQL statement selects from more than one table (e.g. in a join) then PostgreSQL will complain it doesn't know which xmax column you're talking about:

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

In this case you can use the (unfortunately undocumented) _selectable parameter:

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

Which works in a joined tables query just as well as in the case where you're selecting only from one table, so you can always use it if you want.

答案2

得分: 3

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 强制转换为数值类型。)

英文:

One option is to declare xmax in your SA table definition as a system column:

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

This will allow you to access table.c.xmax like any other column (so your proposed table.c.xmax == 0 should then work). The system=True flag tells SA not to attempt to create the xmax column explicitly when emitting CREATE TABLE.

(I've used sa.TEXT as a bit of a workaround here because sqlalchemy.dialects.postgresql doesn't provide an XID datatype, and apparently xid cannot be casted to a numeric type.)

huangapple
  • 本文由 发表于 2020年1月3日 21:06:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/59579151.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定