Oracle Flyway:使用创建视图(通用表格表达式CTE)

Oracle Flyway:使用创建视图(通用表格表达式CTE),oracle,flyway,Oracle,Flyway,如何克服这个错误 Java version: 1.8.0_131, vendor: Oracle Corporation, runtime: C:\Program Files\Java\jdk1.8.0_131\jre [DEBUG] com.oracle:ojdbc8:jar:12.2.0.1.0:provided [INFO] Flyway Community Edition 5.2.4 by Boxfuse [INFO] Database: jdbc:oracle:t

如何克服这个错误

Java version: 1.8.0_131, vendor: Oracle Corporation, runtime: C:\Program Files\Java\jdk1.8.0_131\jre    
[DEBUG]    com.oracle:ojdbc8:jar:12.2.0.1.0:provided    
[INFO] Flyway Community Edition 5.2.4 by Boxfuse
[INFO] Database: jdbc:oracle:thin:@bdlg3400.na.pg.com:1525:ioptd101 (Oracle 12.2)
[DEBUG] Driver  : Oracle JDBC driver 12.2.0.1.0


[ERROR] Migration R__SOME_VIEW_VW.sql failed
[ERROR] --------------------------------------
[ERROR] SQL State  : 42000
[ERROR] Error Code : 933
[ERROR] Message    : ORA-00933: (non-english description)
[ERROR] Location   : sql\Views\R__SOME_VIEW_VW.sql (...\sql\Views\R__SOME_VIEW_VW.sql)
[ERROR] Line       : 7
[ERROR] Statement  : CREATE OR REPLACE VIEW some_view_vw as
[ERROR] WITH
[ERROR] abc AS
[ERROR] (
[ERROR]     SELECT
[ERROR]         iglp.p_skid,
[ERROR]         LISTAGG(g.g_code, ',') WITHIN GROUP (ORDER BY g.g_code) AS lokd_gate_lst
[ERROR]     FROM ig_l_prod iglp
[ERROR]     JOIN ig_prc ig ON ig.ig_skid = iglp.ig_skid
[ERROR]     JOIN g g ON g.g_skid = ig.g_skid
[ERROR]     WHERE iglp.lock_ind = 'Y'
[ERROR]     GROUP BY
[ERROR]         iglp.p_skid
[ERROR] )
[ERROR] SELECT
[ERROR]     pr.p_skid AS scr_prod_skid,
[ERROR]     lg.lokd_gate_lst,
[ERROR]     pr.*
[ERROR] FROM p pr
[ERROR] LEFT JOIN lokd_gate lg ON lg.p_skid = pr.p_skid
[ERROR] where exists(select 1 from PP_PRC pipo WHERE pipo.PI_P_SKID = pr.P_SKID);
[ERROR]
[ERROR] -> [Help 1]

当我将WITH子句作为子查询移动到FROM子句时,脚本就成功了。但以这种方式重构可能会导致其他视图效率低下。

错误消息是
ORA-00933 sql命令未正确结束
,这可能意味着您的查询中有一些禁止或冲突的子句,但根据我的经验,这通常意味着某处缺少逗号或键入错误

首先是一些虚拟表:

create table ig_l_prod(
  p_skid number,
  ig_skid number,
  lock_ind varchar2(1)
);
create table ig_prc(
  ig_skid number,
  g_skid number
);
create table g(
  g_skid number,
  g_code varchar2(1)
);
create table p(
  p_skid number,
  name varchar2(10)
);
create table PP_PRC(
PI_P_SKID number
);
这是来自日志的查询,只需进行一次修改:

CREATE OR REPLACE VIEW some_view_vw as
WITH
lokd_gate AS -- *** Replaced "abc" with "lokd_gate" ***
(
    SELECT
        iglp.p_skid,
        LISTAGG(g.g_code, ',') WITHIN GROUP (ORDER BY g.g_code) AS lokd_gate_lst
    FROM ig_l_prod iglp
    JOIN ig_prc ig ON ig.ig_skid = iglp.ig_skid
    JOIN g g ON g.g_skid = ig.g_skid
    WHERE iglp.lock_ind = 'Y'
    GROUP BY
        iglp.p_skid
)
SELECT
    pr.p_skid AS scr_prod_skid,
    lg.lokd_gate_lst,
    pr.*
FROM p pr
LEFT JOIN lokd_gate lg ON lg.p_skid = pr.p_skid
where exists(select 1 from PP_PRC pipo WHERE pipo.PI_P_SKID = pr.P_SKID);
CTE的别名为
abc
,而连接则为
lokd_gate
——这可能只是清理要在此处发布的视图的一个工件,但如果它在实际的SQL中,则查询有问题

通过模拟表,该SQL在Oracle12c中执行时不会出错


尝试从SQL*Plus执行如上所示的SQL,看看它是否有效。如果是这样的话,那就是框架没有很好地解析CTE(并非闻所未闻)的错误。

根本原因在于Flyway的Oracle解析器:

OracleParser.java

private static final Pattern PLSQL_VIEW_REGEX = Pattern.compile(
        "^CREATE(\\sOR\\sREPLACE)?(\\s(NON)?EDITIONABLE)?\\sVIEW\\s.*\\sAS\\sWITH\\s(PROCEDURE|FUNCTION)");
private static final StatementType PLSQL_VIEW_STATEMENT = new StatementType();

在视图中使用CTE是有效的。你确定你的总体陈述中没有其他错误/遗漏吗?如果您通过SQL*Plus或其他客户机运行相同的脚本,它是否有效?仅从错误消息中的这4行就很难诊断。发布完整视图可能不可取,但您能否创建一个演示该问题的示例?(也不知道为什么你认为它作为子查询效率较低。)@AlexPoole我们在项目中有许多视图,其中许多视图使用了几个CTE。我猜Flyway错误地解析了SQL脚本,只将其中的一部分发送到服务器。你能告诉Flyway按原样使用SQL脚本吗?我不知道Flyway,但是例如,Liquibase有一个“splitStatements”属性用于这类东西,以防止SQL语法出现工具不希望出现的任何问题。我会怀疑日志中语句末尾显示的分号。这是一个语句分隔符(由客户机解释),而不是语句的一部分。它会在JDBC和动态SQL调用等中导致此类错误。删除分号可以解决问题吗?(当然,Flyway可以将其作为脚本处理的一部分;我也不使用它…@AlexPoole,您有使用CTE?Tad的脚本(创建视图)示例吗?谢谢您的回答,但在准备问题时,我忘了在FROM子句中更改lokd_gate的名称。这不是问题所在。这句话在我们的项目中,我们在每次迁移时都会执行,没有问题。然后,最后一句话是正确的:“这是框架的错误,没有很好地解析CTE”,您似乎已经找到了这方面的证据。这很烦人,但不是第一次工具无法正确地接受完全合法的WITH子句。它已在v.6.0.0中修复。最初在