立即执行不与 select into 一起使用
Posted
技术标签:
【中文标题】立即执行不与 select into 一起使用【英文标题】:Execute immediate not working with select into 【发布时间】:2021-04-28 13:35:24 【问题描述】:我有下面的代码,可以正常工作。
SET SERVEROUTPUT ON;
DECLARE
cols CLOB;
BEGIN
SELECT
LISTAGG('"'
|| column_name
|| '"', ',') WITHIN GROUP(
ORDER BY
column_name
)
INTO cols
FROM
all_tab_columns
WHERE
lower(table_name) = 'd_dialler_brut'
AND column_name LIKE 'REASON%';
dbms_output.put_line(cols);
END;
但是,如果我尝试以下代码,则会引发以下错误
错误报告 - ORA-00905: 缺少关键字 ORA-06512: 在第 20 行 00905. 00000 - “缺少关键字”
SET SERVEROUTPUT ON;
DECLARE
cols CLOB;
vstr_cols CLOB;
BEGIN
vstr_cols := q'[
SELECT
LISTAGG('"'
|| column_name
|| '"', ',') WITHIN GROUP(
ORDER BY
column_name
)
INTO cols
FROM
all_tab_columns
WHERE
lower(table_name) = 'd_dialler_brut'
AND column_name LIKE 'REASON%']'
;
EXECUTE IMMEDIATE ( vstr_cols );
dbms_output.put_line(cols);
END;
第二个代码有什么问题?如何避免错误?
【问题讨论】:
【参考方案1】:从您正在构建的SELECT
语句中删除INTO
子句并将其添加到EXECUTE IMMEDIATE
语句中
vstr_cols := q'[
SELECT
LISTAGG('"'
|| column_name
|| '"', ',') WITHIN GROUP(
ORDER BY
column_name
)
FROM
all_tab_columns
WHERE
lower(table_name) = 'd_dialler_brut'
AND column_name LIKE 'REASON%']'
;
EXECUTE IMMEDIATE vstr_cols
INTO cols;
当然,我首先会质疑在这里使用动态 SQL 是否合适。如果您可以使用静态 SQL 做某事,那么您真的应该使用静态 SQL。
我还强烈建议您在执行 SQL 语句之前记录或使用dbms_output
将其写出。否则,你会让自己更难调试。
【讨论】:
谢谢。不确定在执行之前记录 SQL 语句是什么意思。另外,在这种情况下,静态 SQL 与动态 SQL 有什么好处? @jeiv - 记录意味着将其写入表或您的应用程序实现的任何记录机制,以便当您遇到错误时,您可以准确地看到动态构建的查询。将事物保留为静态 SQL 有很多好处——你在编译时而不是在运行时得到编译错误,当出现语法错误时,你会得到更具体的错误,Oracle 会为你跟踪依赖关系,你不必担心关于 SQL 注入攻击之类的事情,您的代码更易于阅读、编写、调试和维护。 @jeiv - 是的,如果你想创建一个表,你需要使用动态 SQL。但是,您希望在存储过程中创建表的情况非常少见。 Oracle 中的表在安装应用程序时创建一次,而不是在运行时创建。我亲自编写 PL/SQL 代码已经有 20 年了,我还没有遇到过我真的想在存储过程中创建表的情况。我见过一些第三方系统在运行时定期创建表,而且它们通常很难管理。 @jeiv - 这真的取决于你在做什么。如果您正在执行数据仓库加载并通过完全重新加载写入暂存表,那么执行截断和重新加载并非不合理。通过merge
语句进行增量加载通常更快,但这可能并不总是可行的。我不确定您要通过动态透视到新创建的表来解决什么问题,所以我不确定该建议什么。但鉴于其他代码不能使用动态创建的表中的数据,除非它也是动态的,我会小心的。
@jeiv - 比删除并重新创建表格更好?是的。识别增量并通过merge
加载它可能是最有效的。以上是关于立即执行不与 select into 一起使用的主要内容,如果未能解决你的问题,请参考以下文章
甲骨文。无法理解 FOR 如何与子查询 SELECT INTO 一起使用
如何将 SQL INSERT INTO SELECT 与 codeigniter 一起使用