英文:
How do I select a PostgreSQL system column using SQLAlchemy?
问题
PostgreSQL在每个表上隐式定义了几个列,例如xmax
和ctid
(参见文档)。
假设我的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.)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论