【问题标题】:How to move CTE for oracle update query in sqlalchemy如何在 sqlalchemy 中为 oracle 更新查询移动 CTE
【发布时间】:2019-09-27 09:45:02
【问题描述】:

我正面临由 sqlalchemy 生成的查询的 oracle 错误 ORA-00928: missing SELECT keyword。这个问题已经被描述并回答了here

我的查询看起来像:

WITH table2 (id) AS (
    SELECT id
    FROM table3
)

UPDATE table SET id=1 
WHERE EXISTS (
    SELECT * 
    FROM table 
    WHERE id IN (SELECT id FROM table2)
)

并由此生成:

table2 = session.query(table3.id).cte()
update(table).where(exists().where(table.id.in_(table2))).values(id=1)

现在我想知道如何告诉 sqlachemy 将 CTE 放在 WHERE 子句中,而不是在 UPDATE 之上。

UPDATE table SET id=1 
WHERE EXISTS (
    WITH table2 (id) AS (
        SELECT id
        FROM table3
    )

    SELECT * 
    FROM table 
    WHERE id IN (SELECT id FROM table2)
)

【问题讨论】:

  • 您的两个更新声明对我来说都有意义。如果table2 中至少存在一行table,为什么要将table 的所有ID 更新为1?这是你真正想要的还是像UPDATE table SET id=1 where id in ( SELECT id FROM table3 ) 这样简单的东西?如果这是您的意图,那么它根本没有理由生成 CTE。此外,您为什么不能简单地运行这样的更新而不是依赖 sqlalchemy 生成的内容?
  • 感谢您的回复。我只是创建了一个最小的示例以使其更易于理解。我的重点是将 WITH 子句移到 SELECT 子句之上。
  • @Hannes 希望有人可以为如何改变 SQLAlchemy 的工作方式提供答案,这将是最干净的解决方案。我对 SQLAlchemy 一无所知,但如果您找不到任何解决方法并且您必须使用现有 SQL,您可能需要查看 SQL Translation Framework。该工具允许我们将完全错误的查询转换为正确的语法。它用于将查询从 SQL Server 转换为 Oracle,但它也可以修复这样的错误。

标签: python database oracle sqlalchemy


【解决方案1】:

CTE 是一种从查询中提取内联视图的好方法,这样做可以使您的代码更易于阅读和维护。

当 CTE 尚未发明时,我们使用内联视图。这里有几个例子(基于 Scott 的模式)来说明我的意思。

首先,CTE:

SQL> with tab as
  2    (select deptno from dept
  3     where deptno > 10
  4    )
  5  select e.deptno, count(*)
  6  from emp e join tab t on t.deptno = e.deptno
  7  group by e.deptno;

    DEPTNO   COUNT(*)
---------- ----------
        30          6
        20          5

它可以移动到内联视图中:

SQL> select e.deptno, count(*)
  2  from emp e join (select deptno from dept
  3                   where deptno > 10
  4                  ) t on t.deptno = e.deptno
  5  group by e.deptno;

    DEPTNO   COUNT(*)
---------- ----------
        30          6
        20          5

或者,使用 old 语法,其中表(在FROM 子句中)用逗号分隔,连接在WHERE 子句中完成(这可能看起来很熟悉):

SQL> select e.deptno, count(*)
  2  from emp e,
  3      (select deptno from dept
  4       where deptno > 10
  5      ) t
  6  where t.deptno = e.deptno
  7  group by e.deptno;

    DEPTNO   COUNT(*)
---------- ----------
        30          6
        20          5

这意味着您的查询可能如下所示;请注意显示您的 CTE 位置的评论:

update table set
  id = 1
  where exists (select *
                from table
                where id in (select id 
                             from 
                               (select id from table3)  --> this line is your CTE
                            )
               );

【讨论】:

  • 我认为 OP 知道如何使用 CTE,他的问题是他不知道如何通过框架正确生成它们。
  • 啊哈。我已经阅读了您在问题下方的赞扬,@Jon;我想我明白你在说什么。另一方面,重新定位 CTE 的查询并将其放入内联视图可能会有所帮助,如果没有其他方法。
  • 是的,最后我不得不回到内联视图。不过还是谢谢
猜你喜欢
  • 2020-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-29
  • 1970-01-01
  • 2015-09-02
  • 1970-01-01
相关资源
最近更新 更多