使用 c# 代码中的函数执行 oracle DDL 脚本
Execute oracle DDL script with functions from c# code
我使用 Oracle 数据库用 C# 代码编写了一些集成测试。测试项目有一个 CreateDatabase.sql,其中包含在每次测试执行时创建整个数据库的 DDL。
当我只有序列和表时,我将此文件的内容拆分为 ";"
字符并分别执行每个创建语句,但现在我有一些函数,它们的语句包含一些 ;
字符,所以我不能再使用这种方法了。
我已经检查了 .NET / Oracle: How to execute a script with DDL statements programmatically 问题,但没有帮助。
1) 如果我尝试在单个 OracleCommand 中执行整个文件内容,我会收到错误 ORA-00911: invalid character
因为 ;
个字符
2) 如果我尝试将文件内容包装在 "begin {0} end;"
中,我会得到一个错误 PLS-00103: Encountered the symbol "CREATE" when expecting one of the following: ...
3) 我可以尝试解析 SQL 文件并将每个语句放入 EXECUTE IMMEDIATE 中,但这会更难...
还有其他选择吗?
我正在使用 Oracle.DataAccess 版本 4.112.3.0 来执行命令。
编辑
@kevinsky 要求一个脚本,这里是一个简化的例子......整个脚本创建了数百个对象......
CREATE SEQUENCE SQ_ARAN_SQ_ARQUIVO_ANEXO;
CREATE OR REPLACE FUNCTION UFC_SPSW_DISP_COMPOSICAO(p_id_composicao IN NUMBER) RETURN NUMBER
IS
retorno NUMBER:= 0;
numeroItens NUMBER;
temDefinicao BOOLEAN := false;
CURSOR item_cur is
select idc.itdc_sq_item_definicao_composi, idc.insu_sq_insumo, idc.comp_sq_composicao, idc.itdc_nr_coeficiente, idc.COMP_DS_COMPOSICAO, idc.comp_sq_composicao_pai
from item_definicao_composicao idc;
BEGIN
FOR item_rec IN item_cur LOOP
temDefinicao := true;
IF (item_rec.itdc_nr_coeficiente is null) THEN
RETURN null;
ELSE
IF (item_rec.insu_sq_insumo is null) THEN
numeroItens := UFC_SPSW_DISP_COMPOSICAO(nvl(item_rec.comp_sq_composicao_pai, item_rec.comp_sq_composicao));
else
retorno := retorno + 1;
END IF;
END IF;
END LOOP;
IF (temDefinicao = false) THEN
RETURN 0;
END IF;
RETURN retorno;
END;
CREATE SEQUENCE SQ_CALC_SQ_CALCULO;
这是一个想法。使前斜杠 /
(单独在单独的一行中)成为终止脚本中每条语句的新标准方式,而不是依赖于分号。例如,您的示例脚本可能会变成:
CREATE SEQUENCE SQ_ARAN_SQ_ARQUIVO_ANEXO
/
CREATE OR REPLACE FUNCTION UFC_SPSW_DISP_COMPOSICAO(p_id_composicao IN NUMBER) RETURN NUMBER
IS
retorno NUMBER:= 0;
numeroItens NUMBER;
temDefinicao BOOLEAN := false;
CURSOR item_cur is
select idc.itdc_sq_item_definicao_composi, idc.insu_sq_insumo, idc.comp_sq_composicao, idc.itdc_nr_coeficiente, idc.COMP_DS_COMPOSICAO, idc.comp_sq_composicao_pai
from item_definicao_composicao idc;
BEGIN
FOR item_rec IN item_cur LOOP
temDefinicao := true;
IF (item_rec.itdc_nr_coeficiente is null) THEN
RETURN null;
ELSE
IF (item_rec.insu_sq_insumo is null) THEN
numeroItens := UFC_SPSW_DISP_COMPOSICAO(nvl(item_rec.comp_sq_composicao_pai, item_rec.comp_sq_composicao));
else
retorno := retorno + 1;
END IF;
END IF;
END LOOP;
IF (temDefinicao = false) THEN
RETURN 0;
END IF;
RETURN retorno;
END;
/
CREATE SEQUENCE SQ_CALC_SQ_CALCULO
/
通过使用 /
,如果您希望使用 SQL*Plus 运行 您的脚本仍然完全有效。但它现在的优点是在 C# 中按语句解析变得微不足道,因此您可以单独执行每个语句而不会出现分号问题。
我过去使用过这种技术并且效果很好。
(如果您不熟悉 Oracle SQL 脚本中斜线的使用,请阅读相关阅读:When do I need to use a semicolon vs a slash in Oracle SQL?。)
我使用正则表达式先行断言仅在 ;
后跟一些保留字(或在文件末尾)进行拆分。
例如:
var statements = Regex.Split(
fileContent,
@"\s*;\s*(?=(?:CREATE|ALTER|DROP|RENAME|TRUNCATE)\s|\s*$)",
RegexOptions.IgnoreCase);
我遇到了同样的问题,已经解决了。
同时使用 'BEGIN END' 和 'EXECUTE IMMEDIATE'.
这是我的测试(成功案例)
begin
EXECUTE IMMEDIATE 'create or replace procedure SP_JHKIM2 IS
begin
dbms_output.put_line(''ABC'');
end;';
end;
我使用 Oracle 数据库用 C# 代码编写了一些集成测试。测试项目有一个 CreateDatabase.sql,其中包含在每次测试执行时创建整个数据库的 DDL。
当我只有序列和表时,我将此文件的内容拆分为 ";"
字符并分别执行每个创建语句,但现在我有一些函数,它们的语句包含一些 ;
字符,所以我不能再使用这种方法了。
我已经检查了 .NET / Oracle: How to execute a script with DDL statements programmatically 问题,但没有帮助。
1) 如果我尝试在单个 OracleCommand 中执行整个文件内容,我会收到错误 ORA-00911: invalid character
因为 ;
个字符
2) 如果我尝试将文件内容包装在 "begin {0} end;"
中,我会得到一个错误 PLS-00103: Encountered the symbol "CREATE" when expecting one of the following: ...
3) 我可以尝试解析 SQL 文件并将每个语句放入 EXECUTE IMMEDIATE 中,但这会更难...
还有其他选择吗?
我正在使用 Oracle.DataAccess 版本 4.112.3.0 来执行命令。
编辑 @kevinsky 要求一个脚本,这里是一个简化的例子......整个脚本创建了数百个对象......
CREATE SEQUENCE SQ_ARAN_SQ_ARQUIVO_ANEXO;
CREATE OR REPLACE FUNCTION UFC_SPSW_DISP_COMPOSICAO(p_id_composicao IN NUMBER) RETURN NUMBER
IS
retorno NUMBER:= 0;
numeroItens NUMBER;
temDefinicao BOOLEAN := false;
CURSOR item_cur is
select idc.itdc_sq_item_definicao_composi, idc.insu_sq_insumo, idc.comp_sq_composicao, idc.itdc_nr_coeficiente, idc.COMP_DS_COMPOSICAO, idc.comp_sq_composicao_pai
from item_definicao_composicao idc;
BEGIN
FOR item_rec IN item_cur LOOP
temDefinicao := true;
IF (item_rec.itdc_nr_coeficiente is null) THEN
RETURN null;
ELSE
IF (item_rec.insu_sq_insumo is null) THEN
numeroItens := UFC_SPSW_DISP_COMPOSICAO(nvl(item_rec.comp_sq_composicao_pai, item_rec.comp_sq_composicao));
else
retorno := retorno + 1;
END IF;
END IF;
END LOOP;
IF (temDefinicao = false) THEN
RETURN 0;
END IF;
RETURN retorno;
END;
CREATE SEQUENCE SQ_CALC_SQ_CALCULO;
这是一个想法。使前斜杠 /
(单独在单独的一行中)成为终止脚本中每条语句的新标准方式,而不是依赖于分号。例如,您的示例脚本可能会变成:
CREATE SEQUENCE SQ_ARAN_SQ_ARQUIVO_ANEXO
/
CREATE OR REPLACE FUNCTION UFC_SPSW_DISP_COMPOSICAO(p_id_composicao IN NUMBER) RETURN NUMBER
IS
retorno NUMBER:= 0;
numeroItens NUMBER;
temDefinicao BOOLEAN := false;
CURSOR item_cur is
select idc.itdc_sq_item_definicao_composi, idc.insu_sq_insumo, idc.comp_sq_composicao, idc.itdc_nr_coeficiente, idc.COMP_DS_COMPOSICAO, idc.comp_sq_composicao_pai
from item_definicao_composicao idc;
BEGIN
FOR item_rec IN item_cur LOOP
temDefinicao := true;
IF (item_rec.itdc_nr_coeficiente is null) THEN
RETURN null;
ELSE
IF (item_rec.insu_sq_insumo is null) THEN
numeroItens := UFC_SPSW_DISP_COMPOSICAO(nvl(item_rec.comp_sq_composicao_pai, item_rec.comp_sq_composicao));
else
retorno := retorno + 1;
END IF;
END IF;
END LOOP;
IF (temDefinicao = false) THEN
RETURN 0;
END IF;
RETURN retorno;
END;
/
CREATE SEQUENCE SQ_CALC_SQ_CALCULO
/
通过使用 /
,如果您希望使用 SQL*Plus 运行 您的脚本仍然完全有效。但它现在的优点是在 C# 中按语句解析变得微不足道,因此您可以单独执行每个语句而不会出现分号问题。
我过去使用过这种技术并且效果很好。
(如果您不熟悉 Oracle SQL 脚本中斜线的使用,请阅读相关阅读:When do I need to use a semicolon vs a slash in Oracle SQL?。)
我使用正则表达式先行断言仅在 ;
后跟一些保留字(或在文件末尾)进行拆分。
例如:
var statements = Regex.Split(
fileContent,
@"\s*;\s*(?=(?:CREATE|ALTER|DROP|RENAME|TRUNCATE)\s|\s*$)",
RegexOptions.IgnoreCase);
我遇到了同样的问题,已经解决了。 同时使用 'BEGIN END' 和 'EXECUTE IMMEDIATE'.
这是我的测试(成功案例)
begin
EXECUTE IMMEDIATE 'create or replace procedure SP_JHKIM2 IS
begin
dbms_output.put_line(''ABC'');
end;';
end;