如何存储和填充 Oracle 中 Execute Immediate 返回的数据?
How to store and populate data returned by Execute Immediate in Oracle?
在我的项目中,我正在尝试执行以下查询:
DECLARE
Sid nvarchar2(30) := ''; /*Here the values will come from some other variable>*/
Bid nvarchar2(30) := ''; /*Here the values will come from some other variable>*/
ExecuteDSQL varchar2(1000);
ExecuteDSQLResult varchar2(10000);
BEGIN
IF Sid IS NULL THEN Sid := '1' ; ELSE Sid := '4' ; END IF;
IF Bid IS NULL THEN Bid := '1' ; ELSE Bid := '5' ; END IF;
ExecuteDSQL := ' SELECT * FROM iftlog WHERE serverid='''|| Sid
|| ''' AND bpid=''' || Bid || ''' ';
EXECUTE IMMEDIATE ExecuteDSQL INTO ExecuteDSQLResult;
DBMS_OUTPUT.PUT_LINE(ExecuteDSQLResult);
END;
/
查询导致数据类型不一致的错误,除了这个错误之外,问题是我们能否像在 MS-SQL 中那样将结果存储到临时 table 中?我是 oracle 数据库的新手。我需要临时 table 来存储 1 到 20 之间的记录,我将使用 Row_Number() 并将在我的项目中相应地修改查询。
在Oracle
中你可以使用
Object type/table type
或
- 动态游标
使用对象 type/table 类型
CREATE TYPE obj_typ AS OBJECT (
id number,
name VARCHAR2(20)
);
/
CREATE TYPE tab_typ AS table of obj_typ;
/
declare
v_type tab_typ :tab_typ();
.....
begin
.....
execute immediate 'select obj_typ(id, name) from tbl' into v_type;
.....
end;
现在您可以将 v_type
用作 temp table
喜欢,
select id from table(v_type);
类型的一个限制是在使用它们之前必须在模式中创建它。
使用动态游标
sql_stmt := 'SELECT * FROM emp WHERE job = :j';
OPEN emp_cv FOR sql_stmt USING my_job;
你必须循环遍历 cursor
才能下注数据的限制不如 temp table
SQL 服务器临时 table 的 Oracle 等价物是一个 PL/SQL 集合。我们可以使用 %rowtype
语法来定义匹配 table 投影的局部类型。我们可以使用该类型将局部变量声明为 selection.
的目标
唉,没有打印记录的便捷机制:您需要在 DBMS_OUTPUT.PUT_LINE() 调用中指定每个单独的列。
这是您用 idomatic 重写的代码 PL/SQL:
DECLARE
Sid nvarchar2(30) := '';/*Here the values will come from some other variable>*/
Bid nvarchar2(30) := '';/*Here the values will come from some other variable>*/
ExecuteDSQL varchar2(1000) := 'SELECT * FROM iftlog WHERE serverid= :1 AND bpid= :2';
type iftlog_nt is table of iftlog%rowtype;
ExecuteDSQLResult iftlog_nt;
BEGIN
IF Sid IS NULL THEN Sid := '1' ; ELSE Sid := '4' ; END IF;
IF Bid IS NULL THEN Bid := '1' ; ELSE Bid := '5' ; END IF;
EXECUTE IMMEDIATE ExecuteDSQL
bulk collect into ExecuteDSQLResult
using sid and bid;
-- loop through all records in PL/SQL table
for idx in 1..ExecuteDSQLResult.count()
loop
DBMS_OUTPUT.PUT_LINE(ExecuteDSQLResult(idx).some_col||'::'||ExecuteDSQLResult(idx).some_other_col);
end loop;
END;
/
当然,像这样重写代码很明显根本不需要动态 SQL。所以我们可以用直接的 select:
替换 EXECUTE IMMEDIATE 调用
SELECT *
bulk collect into ExecuteDSQLResult
FROM iftlog
WHERE serverid= sid
AND bpid= bid;
您也可以使用global temporary table
create global temporary table tmp
(serverid varchar2(10),
bpid varchar2(10),
txt varchar2(100)
)
ON COMMIT PRESERVE ROWS
;
.
DECLARE
Sid varchar2(30) := '1';
Bid varchar2(30) := '1';
ExecuteDSQL varchar2(1000);
BEGIN
ExecuteDSQL := 'insert into tmp
SELECT serverid,bpid,txt FROM iftlog WHERE serverid=:Sid AND bpid=:Bid';
EXECUTE IMMEDIATE ExecuteDSQL using sid, bid;
commit;
END;
/
插入的数据在整个会话期间(在提交保留时)可用,并且可以使用 SQL
访问
select * from tmp;
另见 GTT on SO
在我的项目中,我正在尝试执行以下查询:
DECLARE
Sid nvarchar2(30) := ''; /*Here the values will come from some other variable>*/
Bid nvarchar2(30) := ''; /*Here the values will come from some other variable>*/
ExecuteDSQL varchar2(1000);
ExecuteDSQLResult varchar2(10000);
BEGIN
IF Sid IS NULL THEN Sid := '1' ; ELSE Sid := '4' ; END IF;
IF Bid IS NULL THEN Bid := '1' ; ELSE Bid := '5' ; END IF;
ExecuteDSQL := ' SELECT * FROM iftlog WHERE serverid='''|| Sid
|| ''' AND bpid=''' || Bid || ''' ';
EXECUTE IMMEDIATE ExecuteDSQL INTO ExecuteDSQLResult;
DBMS_OUTPUT.PUT_LINE(ExecuteDSQLResult);
END;
/
查询导致数据类型不一致的错误,除了这个错误之外,问题是我们能否像在 MS-SQL 中那样将结果存储到临时 table 中?我是 oracle 数据库的新手。我需要临时 table 来存储 1 到 20 之间的记录,我将使用 Row_Number() 并将在我的项目中相应地修改查询。
在Oracle
中你可以使用
Object type/table type
或- 动态游标
使用对象 type/table 类型
CREATE TYPE obj_typ AS OBJECT (
id number,
name VARCHAR2(20)
);
/
CREATE TYPE tab_typ AS table of obj_typ;
/
declare
v_type tab_typ :tab_typ();
.....
begin
.....
execute immediate 'select obj_typ(id, name) from tbl' into v_type;
.....
end;
现在您可以将 v_type
用作 temp table
喜欢,
select id from table(v_type);
类型的一个限制是在使用它们之前必须在模式中创建它。
使用动态游标
sql_stmt := 'SELECT * FROM emp WHERE job = :j';
OPEN emp_cv FOR sql_stmt USING my_job;
你必须循环遍历 cursor
才能下注数据的限制不如 temp table
SQL 服务器临时 table 的 Oracle 等价物是一个 PL/SQL 集合。我们可以使用 %rowtype
语法来定义匹配 table 投影的局部类型。我们可以使用该类型将局部变量声明为 selection.
唉,没有打印记录的便捷机制:您需要在 DBMS_OUTPUT.PUT_LINE() 调用中指定每个单独的列。
这是您用 idomatic 重写的代码 PL/SQL:
DECLARE
Sid nvarchar2(30) := '';/*Here the values will come from some other variable>*/
Bid nvarchar2(30) := '';/*Here the values will come from some other variable>*/
ExecuteDSQL varchar2(1000) := 'SELECT * FROM iftlog WHERE serverid= :1 AND bpid= :2';
type iftlog_nt is table of iftlog%rowtype;
ExecuteDSQLResult iftlog_nt;
BEGIN
IF Sid IS NULL THEN Sid := '1' ; ELSE Sid := '4' ; END IF;
IF Bid IS NULL THEN Bid := '1' ; ELSE Bid := '5' ; END IF;
EXECUTE IMMEDIATE ExecuteDSQL
bulk collect into ExecuteDSQLResult
using sid and bid;
-- loop through all records in PL/SQL table
for idx in 1..ExecuteDSQLResult.count()
loop
DBMS_OUTPUT.PUT_LINE(ExecuteDSQLResult(idx).some_col||'::'||ExecuteDSQLResult(idx).some_other_col);
end loop;
END;
/
当然,像这样重写代码很明显根本不需要动态 SQL。所以我们可以用直接的 select:
替换 EXECUTE IMMEDIATE 调用SELECT *
bulk collect into ExecuteDSQLResult
FROM iftlog
WHERE serverid= sid
AND bpid= bid;
您也可以使用global temporary table
create global temporary table tmp
(serverid varchar2(10),
bpid varchar2(10),
txt varchar2(100)
)
ON COMMIT PRESERVE ROWS
;
.
DECLARE
Sid varchar2(30) := '1';
Bid varchar2(30) := '1';
ExecuteDSQL varchar2(1000);
BEGIN
ExecuteDSQL := 'insert into tmp
SELECT serverid,bpid,txt FROM iftlog WHERE serverid=:Sid AND bpid=:Bid';
EXECUTE IMMEDIATE ExecuteDSQL using sid, bid;
commit;
END;
/
插入的数据在整个会话期间(在提交保留时)可用,并且可以使用 SQL
访问select * from tmp;
另见 GTT on SO