You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Entity Framework执行带COMMIT的INSERT ALL时遇ORA-00933错误

Entity Framework迁移执行Oracle SQL文件遇ORA-00933错误的解决办法

问题重现

使用Entity Framework迁移时,通过SqlResource读取SQL文件执行数据导入,代码如下:

迁移代码:

public override void Up()
{
    this.SqlResource("Migrations.SqlMigrations.ImportData.sql");
}

执行命令:

Update-Database -SourceMigration 0 -StartUpProjectName Test

SQL文件内容(简化版):

INSERT ALL 
INTO PLZ (PLZ_PK, PLZ, LOCATION, CREATION_DATE, CREATED_BY) 
VALUES ('1', '111111', 'Testcity1', to_timestamp('15.12.09 09:15:00,000000000'), 'Init Dateimport')
INTO PLZ (PLZ_PK, PLZ, LOCATION, CREATION_DATE, CREATED_BY) 
VALUES ('2', '222222', 'Testcity2', to_timestamp('15.12.09 09:15:00,000000000'), 'Init Dateimport')
...
SELECT * FROM dual
COMMIT

INSERT ALL 
INTO PLZ (PLZ_PK, PLZ, LOCATION, CREATION_DATE, CREATED_BY) 
VALUES ('3', '333333', 'Testcity3', to_timestamp('15.12.09 09:15:00,000000000'), 'Init Dateimport')
...
SELECT * FROM dual

注:省略号表示中间包含500条数据,该写法在Oracle SQL Developer中可正常运行,但EF执行时抛出ORA-00933: SQL command not properly ended错误。

问题原因

  1. EF默认将整个SQL文件视为单条命令执行,而Oracle不允许在普通SQL语句中直接使用COMMIT,必须包裹在PL/SQL块内。
  2. 多个INSERT ALL块直接拼接时,EF的语句解析逻辑无法正确分割独立命令,导致语法识别错误。

解决方案

方案1:用PL/SQL块包裹SQL内容

修改SQL文件,将所有语句放在BEGIN...END;块中,让Oracle能正确处理COMMIT命令:

BEGIN
    INSERT ALL 
    INTO PLZ (PLZ_PK, PLZ, LOCATION, CREATION_DATE, CREATED_BY) 
    VALUES ('1', '111111', 'Testcity1', to_timestamp('15.12.09 09:15:00,000000000'), 'Init Dateimport')
    INTO PLZ (PLZ_PK, PLZ, LOCATION, CREATION_DATE, CREATED_BY) 
    VALUES ('2', '222222', 'Testcity2', to_timestamp('15.12.09 09:15:00,000000000'), 'Init Dateimport')
    ...
    SELECT * FROM dual;
    COMMIT;
    
    INSERT ALL 
    INTO PLZ (PLZ_PK, PLZ, LOCATION, CREATION_DATE, CREATED_BY) 
    VALUES ('3', '333333', 'Testcity3', to_timestamp('15.12.09 09:15:00,000000000'), 'Init Dateimport')
    ...
    SELECT * FROM dual;
    COMMIT;
END;
/

此方式将整个内容作为单条PL/SQL命令执行,既符合Oracle语法要求,也适配EF的命令解析逻辑。

方案2:在EF迁移中拆分执行语句

若不想修改SQL文件,可在Up方法中拆分SQL内容,逐块调用Sql方法执行:

public override void Up()
{
    // 执行第一个INSERT ALL块及COMMIT
    this.Sql(@"INSERT ALL 
INTO PLZ (PLZ_PK, PLZ, LOCATION, CREATION_DATE, CREATED_BY) 
VALUES ('1', '111111', 'Testcity1', to_timestamp('15.12.09 09:15:00,000000000'), 'Init Dateimport')
...
SELECT * FROM dual;
COMMIT;");

    // 执行第二个INSERT ALL块
    this.Sql(@"INSERT ALL 
INTO PLZ (PLZ_PK, PLZ, LOCATION, CREATION_DATE, CREATED_BY) 
VALUES ('3', '333333', 'Testcity3', to_timestamp('15.12.09 09:15:00,000000000'), 'Init Dateimport')
...
SELECT * FROM dual;");
}

此方式需确保每个语句块是独立的合法Oracle命令,适合SQL结构清晰的场景。

额外注意点

  • Oracle的INSERT ALL语句必须以SELECT * FROM dual;结尾,且分号不能省略,否则会触发语法错误。
  • 普通SQL语句中禁止直接使用COMMIT,必须放在PL/SQL块内或作为独立命令执行。

内容的提问来源于stack exchange,提问作者optPr1me

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 19:07:31