繁体   English   中英

SQLAlchemy With Clause (CTE) with Insert 未正确编译 Oracle

[英]SQLAlchemy With Clause (CTE) with Insert is not compiling correctly for Oracle

我正在尝试在 SQLAlchemy 中为 Oracle 12CR1 数据库生成以下设计的 DML 语句:

INSERT INTO baz (name, qty)
WITH bar AS (
    SELECT bar.name, bar.qty
    FROM bar
)
SELECT foo.name, bar.qty
FROM foo JOIN bar ON foo.name = bar.name

但是,SQLAlchemy 似乎是乱序生成的,如下所示:

WITH bar AS (
    SELECT bar.name, bar.qty
    FROM bar
)
INSERT INTO baz (name, qty)
SELECT foo.name, bar.qty
FROM foo JOIN bar ON foo.name = bar.name

乱序执行失败并显示ORA-00923: FROM keyword not found where expected

我的理论是 SQLAlchemy 假设 PostgreSQL 语法是WITH... INSERT INTO... SELECT...并且不尊重 Oracle 语法是INSERT INTO... WITH... SELECT...

有什么方法可以使它与 Oracle 一起使用,或者至少有一种方法可以修改insert().from_select()的编译方式?

重现:

from sqlalchemy import (Table, Column, String, Integer,
                    MetaData, select, func)
from sqlalchemy.dialects import oracle


metadata = MetaData()

foo = Table('foo', metadata, Column('name', String))
bar = Table('bar', metadata, Column('name', String), Column('qty', Integer))
baz = Table('baz', metadata, Column('name', String), Column('qty', Integer))

with_bar = select([bar.c.name, bar.c.qty]).cte('bar')
sel = select([foo.c.name, with_bar.c.qty])
sel = sel.select_from(
        foo.join(with_bar, 
                 foo.c.name == with_bar.c.name
                 )
)

ins = baz.insert().from_select([baz.c.name, baz.c.qty], sel)
print ins.compile(dialect=oracle.dialect())

您将需要对语句进行自定义呈现。 这是帮助我解决另一种方言的这个确切问题的代码(我已将其更改为 oracle)

from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.expression import ClauseElement, Executable

class InsertFromSelect(Executable, ClauseElement):
    def __init__(self, table, select):
        self.table = table
        self.select = select

@compiles(InsertFromSelect, "oracle")
def visit_insert_from_select(element, compiler, **kw):
    return "INSERT INTO %s (%s)" % (
        compiler.process(element.table, asfrom=True, **kw),
        compiler.process(element.select, **kw)
    )

#target table to insert
table = sqlalchemy.Table('foo' MetaData=())
#statement with a CTE / WITH clause
baz = select().select_from(sqlalchemy.text('select * from bar').columns().cte())

#print or run the new statement, correctly ordered
print(
    InsertFromSelect(table,baz)
)

本质上,您将创建一个新元素InsertFromSelect ,它分别保存查询和插入,然后创建一个将它们呈现在正确位置的编译访问器。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM