我有一个表(我们将其命名为source_tab),其中我存储了符合某些条件的所有数据库表的列表。
tab_name: description:
table1 some_desc1
table2 some_desc2
现在我需要在每个表上执行select语句并将结果作为表返回(我创建了自定义TYPE)。但是我有一个问题 - 使用批量收集时,只返回最后一个select语句。打开游标也是同样的问题。有没有可能实现这个目标,另一个是使用union all连接所有select语句并将其作为一个语句执行?因为我是sql的初学者,我的第二个问题是,在sql注入问题方面使用这个动态sql是否可以?以下是我的代码的简化版本:
CREATE OR REPLACE FUNCTION my_function RETURN newly_created_table_type IS
ret_tab_type newly_created_table_type;
BEGIN
for r in (select * from source_tab)
loop
execute immediate 'select value1, value2,''' || r.tab_name || ''' from ' || r.tab_name bulk collect into ret_tab_type;
end loop;
return ret_tab_type;
END;
我正在使用Oracle 11。
答案 0 :(得分:0)
如果要从所有表中检索的列的数量和类型相同,可以在执行前使用UNION ALL
将所有查询合并为一个。
CREATE OR REPLACE FUNCTION my_function
RETURN newly_created_table_type
IS
ret_tab_type newly_created_table_type;
v_query VARCHAR2 (4000);
BEGIN
SELECT LISTAGG (' select VALUE1,VALUE2 FROM ' || tab_name, ' UNION ALL ')
WITHIN GROUP (ORDER BY tab_name)
INTO v_query
FROM source_tab;
EXECUTE IMMEDIATE v_query BULK COLLECT INTO ret_tab_type;
RETURN ret_tab_type;
END;
然后,您可以使用单个select语句来获取所有值。
select * FROM TABLE ( my_function );
答案 1 :(得分:0)
在您的情况下,您尝试动态填充集合并希望将结果放在单个集合中。在你的情况下,它不可能在一个循环中这样做。同样正如@OldProgrammer所提到的,从性能角度来看,piperow将是一个更好的解决方案。见下面的演示:
- 表格和值:
CREATE TABLE SOURCE_TAB(TAB_NAME VARCHAR2(100), DESCRIPTION VARCHAR2(100));
/
SELECT * FROM SOURCE_TAB;
/
INSERT INTO SOURCE_TAB VALUES('table1','some_desc1');
INSERT INTO SOURCE_TAB VALUES('table2','some_desc2');
/
CREATE TABLE TABLE1(COL1 NUMBER, COL2 NUMBER);
/
INSERT INTO TABLE1 VALUES(1,2);
INSERT INTO TABLE1 VALUES(3,4);
INSERT INTO TABLE1 VALUES(5,6);
/
Select * from TABLE1;
/
CREATE TABLE TABLE2(COL1 NUMBER, COL2 NUMBER);
/
INSERT INTO TABLE2 VALUES(7,8);
INSERT INTO TABLE2 VALUES(9,10);
INSERT INTO TABLE2 VALUES(11,12);
/
Select * from TABLE2;
/
- 对象已创建
--UDT
CREATE OR REPLACE TYPE NEWLY_CREATED_TABLE_TYPE IS OBJECT (
VALUE1 NUMBER,
VALUE2 NUMBER
);
/
--Type of UDT
CREATE OR TYPE NEWLY_CRTD_TYP AS TABLE OF NEWLY_CREATED_TABLE_TYPE;
/
- 功能:
--Function
CREATE OR REPLACE FUNCTION MY_FUNCTION
RETURN NEWLY_CRTD_TYP PIPELINED
AS
CURSOR CUR_TAB
IS
SELECT *
FROM SOURCE_TAB;
RET_TAB_TYPE NEWLY_CRTD_TYP;
BEGIN
FOR I IN CUR_TAB
LOOP
--Here i made sure that all the tables have col1 & col2 columns since you are using dynamic sql.
EXECUTE IMMEDIATE 'select NEWLY_CREATED_TABLE_TYPE(COL1, COL2) from '|| I.TAB_NAME
BULK COLLECT INTO RET_TAB_TYPE;
EXIT WHEN CUR_TAB%NOTFOUND;
FOR REC IN 1 .. RET_TAB_TYPE.COUNT
LOOP
PIPE ROW (RET_TAB_TYPE (REC) );
END LOOP;
END LOOP;
RETURN;
END;
/
输出:
SQL> Select * from table(MY_FUNCTION);
VALUE1 VALUE2
---------- ----------
1 2
3 4
5 6
7 8
9 10
11 12
6 rows selected.