SQLAlchemy 与多列相关更新?
SQLAlchemy Correlated Update with Multiple Columns?
这个问题已在 Whosebug 上被问过多次,但它们似乎都超过一年了,所以我想我会再问一次,以防有更新。
A correlated update
是一个更新语句,它根据另一个 table 的值更新一个 table 中的所有行,同时将两个 table 链接在一起。
从 SQLAlchemy docs 开始,我们可以轻松地进行相关更新,但只能在单个列上进行:
update(foo).values(bar=select([foobar.c.bar]).where(foobar.c.id == foo.c.id))
这转化为:
UPDATE foo
SET bar = (
SELECT bar
FROM foobar
WHERE foobar.id = foo.id
)
我们如何在 sqlalchemy 中使用多个列来编写相关更新?例如:
UPDATE foo
SET (bar, baz) = (
SELECT bar, baz
FROM foobar
WHERE foobar.id = foo.id
)
根据您的头像和描述,我猜您使用的是 Oracle。来自 this answer one can device the following SQLAlchemy concotion, if your join results in a key preserved view:
stmt = select([foo.c.bar.label('foo_bar'),
foo.c.baz.label('foo_baz'),
foobar.c.bar.label('foobar_bar'),
foobar.c.baz.label('foobar_baz')]).\
where(foo.c.id == foobar.c.id)
update(stmt).values({stmt.c.foo_bar: stmt.c.foobar_bar,
stmt.c.foo_baz: stmt.c.foobar_baz})
产生以下 SQL:
UPDATE (SELECT foo.bar AS foo_bar,
foo.baz AS foo_baz,
foobar.bar AS foobar_bar,
foobar.baz AS foobar_baz
FROM foo, foobar
WHERE foo.id = foobar.id)
SET foo_bar=foobar_bar, foo_baz=foobar_baz
标签很重要,因为您的表共享列名。
你也可以生成你原来的目标SQL:
from sqlalchemy import tuple_, select, exists
stmt = select([foobar.c.bar, foobar.c.baz]).where(foo.c.id == foobar.c.id)
foo.update().\
values({tuple_(foo.c.bar, foo.c.baz).self_group(): stmt}).\
where(exists(stmt))
self_group()
调用很重要,因为编译器似乎忽略了元组周围的括号,在这种情况下会产生不正确的语法。我添加了 WHERE 子句以避免更新 foo 没有匹配 foobar:
的行
UPDATE foo SET (bar, baz)=(SELECT foobar.bar, foobar.baz
FROM foobar
WHERE foo.id = foobar.id) WHERE EXISTS (SELECT foobar.bar, foobar.baz
FROM foobar
WHERE foo.id = foobar.id)
这个问题已在 Whosebug 上被问过多次,但它们似乎都超过一年了,所以我想我会再问一次,以防有更新。
A correlated update
是一个更新语句,它根据另一个 table 的值更新一个 table 中的所有行,同时将两个 table 链接在一起。
从 SQLAlchemy docs 开始,我们可以轻松地进行相关更新,但只能在单个列上进行:
update(foo).values(bar=select([foobar.c.bar]).where(foobar.c.id == foo.c.id))
这转化为:
UPDATE foo
SET bar = (
SELECT bar
FROM foobar
WHERE foobar.id = foo.id
)
我们如何在 sqlalchemy 中使用多个列来编写相关更新?例如:
UPDATE foo
SET (bar, baz) = (
SELECT bar, baz
FROM foobar
WHERE foobar.id = foo.id
)
根据您的头像和描述,我猜您使用的是 Oracle。来自 this answer one can device the following SQLAlchemy concotion, if your join results in a key preserved view:
stmt = select([foo.c.bar.label('foo_bar'),
foo.c.baz.label('foo_baz'),
foobar.c.bar.label('foobar_bar'),
foobar.c.baz.label('foobar_baz')]).\
where(foo.c.id == foobar.c.id)
update(stmt).values({stmt.c.foo_bar: stmt.c.foobar_bar,
stmt.c.foo_baz: stmt.c.foobar_baz})
产生以下 SQL:
UPDATE (SELECT foo.bar AS foo_bar,
foo.baz AS foo_baz,
foobar.bar AS foobar_bar,
foobar.baz AS foobar_baz
FROM foo, foobar
WHERE foo.id = foobar.id)
SET foo_bar=foobar_bar, foo_baz=foobar_baz
标签很重要,因为您的表共享列名。
你也可以生成你原来的目标SQL:
from sqlalchemy import tuple_, select, exists
stmt = select([foobar.c.bar, foobar.c.baz]).where(foo.c.id == foobar.c.id)
foo.update().\
values({tuple_(foo.c.bar, foo.c.baz).self_group(): stmt}).\
where(exists(stmt))
self_group()
调用很重要,因为编译器似乎忽略了元组周围的括号,在这种情况下会产生不正确的语法。我添加了 WHERE 子句以避免更新 foo 没有匹配 foobar:
UPDATE foo SET (bar, baz)=(SELECT foobar.bar, foobar.baz
FROM foobar
WHERE foo.id = foobar.id) WHERE EXISTS (SELECT foobar.bar, foobar.baz
FROM foobar
WHERE foo.id = foobar.id)