SQLAlchemy多列相关更新?

时间:2017-03-05 20:46:47

标签: python python-2.7 sqlalchemy correlated-subquery

这个问题已在stackoverflow上被多次询问,但它们似乎都已超过一年了,所以我想我会再次询问是否有更新。

correlated update是一个更新语句,它根据另一个表中的值更新一个表中的所有行,同时将两个表链接在一起。

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
) 

1 个答案:

答案 0 :(得分:2)

根据您的头像和说明,我猜测您正在使用Oracle。从this answer开始,如果您的加入产生key preserved view,则可以设置以下SQLAlchemy concotion:

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)