获得所需结果的一个选项是使用pipelined functions。它们以表格的形式提供结果。
顺便说一句,您的查询并不完全正确,因为您需要加入更多元素。这就是为什么总是最好使用ANSI 语法。但是,我会保留您的语法,以便您更轻松地进行解释。
让我给你看一个例子。我没有version这个字段,所以我用的是行数:
首先我们需要创建两种类型,一种为object,另一种为table of。第一个是行,第二个是建表。
SQL> CREATE OR REPLACE TYPE t_tf_row AS OBJECT ( username varchar2(40), created_date date, size_mb varchar2(10), counter number );
/
Type created.
SQL> CREATE TYPE t_tf_tab IS TABLE OF t_tf_row;
/
Type created.
现在,我们创建一个与您的非常相似的pipelined function。
SQL> CREATE OR REPLACE FUNCTION get_schema_details RETURN t_tf_tab PIPELINED
AS
v_sql varchar2(4000);
v_counter pls_integer;
BEGIN
for h in
(
select o.owner
, o.object_name
, u.created
, round(ds.bytes/1024/1024/1024) as table_size
from dba_users u
, dba_objects o
, dba_segments ds
WHERE u.account_status = 'OPEN'
and u.DEFAULT_TABLESPACE not in ('SYSAUX','SYSTEM')
and u.username=o.owner
and u.username=ds.owner
and o.object_name = ds.segment_name
and o.object_type = ds.segment_type
and o.object_name='ODSPOSTING'
and o.object_type='TABLE'
)
loop
v_sql := 'select count(*) from '||h.owner||'.'||h.object_name;
EXECUTE IMMEDIATE v_sql into v_counter;
PIPE ROW(t_tf_row(h.owner,h.created,h.table_size,v_counter));
end loop;
END;
/
Function created.
SQL> select * from table(get_schema_details());
USERNAME CREATED_D SIZE_MB COUNTER
---------------------------------------- --------- ---------- ----------
ODSVIEWS 24-MAR-20 14 71853408
ALFAODS 20-DEC-19 14 71853408
您可以根据需要使函数动态化,例如引入输入参数而不是硬编码值。
更新
您的测试用例场景
SQL> CREATE USER SCHEMA1 IDENTIFIED BY Oracle_1234
DEFAULT TABLESPACE USERS
TEMPORARY TABLESPACE TEMP_GROUP; 2 3
User created.
SQL> GRANT CREATE TABLE TO SCHEMA1;
Grant succeeded.
SQL> GRANT UNLIMITED TABLESPACE TO SCHEMA1;
Grant succeeded.
SQL> CREATE USER SCHEMA2 IDENTIFIED BY Oracle_1234
DEFAULT TABLESPACE USERS
TEMPORARY TABLESPACE TEMP_GROUP;
User created.
SQL> GRANT CREATE TABLE TO SCHEMA2;
Grant succeeded.
SQL> GRANT UNLIMITED TABLESPACE TO SCHEMA2;
Grant succeeded.
SQL> CREATE TABLE SCHEMA1.MASTER(VERSION VARCHAR2(6 BYTE));
Table created.
SQL> CREATE TABLE SCHEMA2.MASTER(VERSION VARCHAR2(6 BYTE));
Table created.
SQL> INSERT INTO "SCHEMA1"."MASTER" (VERSION) VALUES ('1.1.0');
1 row created.
SQL> COMMIT;
Commit complete.
SQL> INSERT INTO "SCHEMA2"."MASTER" (VERSION) VALUES ('2.2.0');
1 row created.
SQL> COMMIT;
Commit complete.
现在我们创建类型和函数。
SQL> CREATE OR REPLACE TYPE t_tf_row AS OBJECT ( username varchar2(40), created_date DATE, size_mb varchar2(10), counter NUMBER );
2 /
Type created.
SQL> CREATE OR REPLACE TYPE t_tf_tab IS TABLE OF t_tf_row;
2 /
Type created.
SQL> CREATE OR REPLACE FUNCTION get_master_version_details RETURN t_tf_tab PIPELINED
AS
v_sql varchar2(4000);
2 3 4 v_counter pls_integer;
BEGIN
5 6 FOR h IN
(
SELECT o.owner
7 8 9 , o.object_name
, u.created
, round(ds.bytes/1024/1024/1024) AS table_size
10 11 12 FROM dba_users u
, dba_objects o
, dba_segments ds
13 14 15 WHERE u.account_status = 'OPEN'
AND u.DEFAULT_TABLESPACE NOT IN ('SYSAUX','SYSTEM')
AND u.username=o.owner
16 17 18 AND u.username=ds.owner
AND o.object_name = ds.segment_name
AND o.object_type = ds.segment_type
19 20 21 AND o.object_name='MASTER'
AND o.object_type='TABLE'
)
22 23 24 loop
v_sql := 'select count(*) from '||h.owner||'.'||h.object_name;
EXECUTE IMMEDIATE v_sql INTO v_counter;
25 26 27 PIPE ROW(t_tf_row(h.owner,h.created,h.table_size,v_counter));
END loop;
END;
28 29 30 /
Function created.
SQL> SELECT COUNT(*) FROM all_objects WHERE object_name='MASTER' AND object_type='TABLE';
COUNT(*)
----------
2
SQL> SELECT * FROM TABLE(get_master_version_details());
USERNAME CREATED_D SIZE_MB COUNTER
---------------------------------------- --------- ---------- ----------
SCHEMA1 28-SEP-21 0 1
SCHEMA2 28-SEP-21 0 1
为什么在您的情况下不起作用?您必须在具有正确权限的用户/模式中安装函数和类型才能运行您正在执行的操作。
在上面的示例中,作为测试,我确实在我的 sys 架构上安装了函数和类型(你不应该这样做)。所以,让我们删除函数和类型,并为此创建一个额外的用户,我们称之为schema3
SQL> DROP TYPE t_tf_tab;
Type dropped.
SQL> DROP TYPE t_tf_row;
Type dropped.
SQL> DROP FUNCTION get_master_version_details;
Function dropped.
SQL> create user schema3 identified by Oracle_1234 default tablespace users temporary tablespace temp_group ;
User created.
SQL> grant select any table, create procedure, create table, select any dictionary to schema3 ;
Grant succeeded.
SQL> CREATE OR REPLACE TYPE schema3.t_tf_row AS OBJECT ( username varchar2(40), created_date DATE, size_mb varchar2(10), counter NUMBER );
2 /
Type created.
SQL> CREATE OR REPLACE TYPE schema3.t_tf_tab IS TABLE OF t_tf_row;
2 /
Type created.
SQL> CREATE OR REPLACE FUNCTION schema3.get_master_version_details RETURN t_tf_tab PIPELINED
AS
v_sql varchar2(4000);
v_counter pls_integer;
BEGIN
2 3 4 5 6 FOR h IN
7 (
SELECT o.owner
, o.object_name
8 9 10 , u.created
, round(ds.bytes/1024/1024/1024) AS table_size
FROM dba_users u
, dba_objects o
, dba_segments ds
WHERE u.account_status = 'OPEN'
11 12 13 14 15 16 AND u.DEFAULT_TABLESPACE NOT IN ('SYSAUX','SYSTEM')
AND u.username=o.owner
AND u.username=ds.owner
17 18 19 AND o.object_name = ds.segment_name
AND o.object_type = ds.segment_type
AND o.object_name='MASTER'
20 21 22 AND o.object_type='TABLE'
23 )
loop
24 25 v_sql := 'select count(*) from '||h.owner||'.'||h.object_name;
EXECUTE IMMEDIATE v_sql INTO v_counter;
PIPE ROW(t_tf_row(h.owner,h.created,h.table_size,v_counter));
26 27 28 END loop;
END;
/ 29 30
Function created.
SQL> SELECT * FROM TABLE(schema3.get_master_version_details());
USERNAME CREATED_D SIZE_MB COUNTER
---------------------------------------- --------- ---------- ----------
SCHEMA1 28-SEP-21 0 1
SCHEMA2 28-SEP-21 0 1
请注意我授予schema3 的权限以使流水线功能正常工作。