How to perform a dynamic select query for multiple tables in oracle? using table name and column names as values from other table? - sql

i have a table having columns such schema name,table name,column name.
schema name
table name
column name
dbo
product
colour
dbo
sales
quantity
dbo
customer
order
i want to perform an action such that to get a count of records based on column as column name and table as table name
select count(colour) as count from dbo.product
select count(quantity) as count from dbo.sales
select count(order) as count from dbo.customer
can u suggest me correct steps to achieve this using Oracle database. thanks in advance
expected output
count
5
50
150

If you need to get count per column per table, you can do this with plain SQL using DBMS_XMLGEN package, which essentially executes new cursors dynamically.
I think you can adapt the example query below to suit your needs (aggregate counts or convert them to another format).
with a as (
select
'all_tables' as table_name, 'table_name' as column_name
from dual
union all
select 'all_tables', 'tablespace_name' from dual union all
select 'all_tab_cols', 'column_name' from dual union all
select 'all_indexes', 'index_name' from dual union all
select 'all_indexes', 'tablespace_name' from dual
)
select
table_name,
column_name,
cast(extractvalue(
dbms_xmlgen.getxmltype(
'select count(' || column_name || ') as cnt' || chr(10) ||
'from ' || table_name
),
'/ROWSET/ROW/CNT'
) as int) as cnt
from a
TABLE_NAME | COLUMN_NAME | CNT
:----------- | :-------------- | ----:
all_tables | table_name | 71
all_tables | tablespace_name | 43
all_tab_cols | column_name | 20983
all_indexes | index_name | 81
all_indexes | tablespace_name | 73
db<>fiddle here

You cannot do this in pure sql, but you can pretty easily do this in pl/sql. In the code below I'm storing the results in a table called rowcounts and it assumes your table with tables and column names is called
CREATE table mytables (schema_name VARCHAR2(100), table_name, VARCHAR2(100), column_name VARCHAR2(100));
INSERT INTO mytables (schema_name, table_name, column_name) VALUES ('dbo','product','colour');
INSERT INTO mytables (schema_name, table_name, column_name) VALUES ('dbo','sales','quantity');
INSERT INTO mytables (schema_name, table_name, column_name) VALUES ('dbo','customer','order');
CREATE TABLE rowcounts (table_name VARCHAR2(500), rowcount NUMBER);
DECLARE
l_rowcount INT;
BEGIN
FOR r IN (SELECT * FROM mytables) LOOP
EXECUTE IMMEDIATE 'SELECT COUNT('||r.column_name||') FROM '||r.table_name INTO l_rowcount;
--dbms_output.put_line('SELECT COUNT('||r.column_name||') FROM '||r.table_name);
INSERT INTO rowcounts(table_name, rowcount) VALUES (r.table_name, l_rowcount);
END LOOP;
COMMIT;
END;
/
--DROP TABLE rowcounts;

Related

How to read the same column from every table in a database?

I have a huge database with 400+ tables. Each table has the same column id for the Primary key and "timestamp_modify" in which the last change of the table is done.
So what I want are 2 things:
Now I want a list of all changes by ID and table name like:
Table | id | timestamp_modiy
Kid | 1 | 24.10.2021 00:01
Parent | 1000 | 24.10.2021 00:02
The only, very bad way I could come up with, is that I make a view in which I include every damn table by hand and read out the values...
Is there a better way?
How about a pipelined function?
Just setting datetime format (you don't have to do that):
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
Types:
SQL> create or replace type t_row as object
2 (table_name varchar2(30),
3 id number,
4 timestamp_modify date)
5 /
Type created.
SQL> create or replace type t_tab is table of t_row;
2 /
Type created.
Function: querying user_tab_columns, its cursor FOR loop fetches tables that contain both ID and TIMESTAMP_MODIFY columns, dynamically creates select statement to return the last (MAX function, to avoid too_many_rows) columns' values for the last TIMESTAMP_MODIFY value (returned by the subquery).
SQL> create or replace function f_test
2 return t_tab pipelined
3 as
4 l_str varchar2(500);
5 l_id number;
6 l_timestamp_modify date;
7 begin
8 for cur_r in (select table_name from user_tab_columns
9 where column_name = 'ID'
10 intersect
11 select table_name from user_tab_columns
12 where column_name = 'TIMESTAMP_MODIFY'
13 )
14 loop
15 l_str := 'select max(a.id) id, max(a.timestamp_modify) timestamp_modify ' ||
16 'from ' || cur_r.table_name || ' a ' ||
17 'where a.timestamp_modify = ' ||
18 ' (select max(b.timestamp_modify) ' ||
19 ' from ' || cur_r.table_name || ' b ' ||
20 ' where b.id = a.id)';
21 execute immediate l_str into l_id, l_timestamp_modify;
22 pipe row(t_row(cur_r.table_name, l_id, l_timestamp_modify));
23 end loop;
24 end;
25 /
Function created.
Testing:
SQL> select * from table(f_test);
TABLE_NAME ID TIMESTAMP_MODIFY
------------------------------ ---------- -------------------
TABA 1 24.10.2021 14:59:29
TAB_1 1 24.10.2021 15:03:16
TAB_2 25 24.10.2021 15:03:36
TEST 5 24.10.2021 15:04:24
SQL>
Yes, the only way is to union all all tables, like:
select id, timestamp_modify
from kid
union all
select id, timestamp_modify
from parent
union all
...
The performance will be awful, since all the tables will be scanned every time :(
I think that you might reconsider you db design...
You can build a procedure for this, but even so it will have some impact in performance. Although there is a loop, with SQL Dynamic, you might only need 400 iterations, and in each one you will insert all the ids of that table.
I am taking some assumptions
You want all the IDs and their corresponding timestamp_modify per table
I create a table to store the results. If you use it with the same name always it will recycle the object. If you not, you can keep a history
I am assuming that only one timestamp_modify row is present per ID
I filter only the tables of your schema that contain both columns.
The table contains also the table_name that you can identify where the record is coming from.
One example
create or replace procedure pr_build_output ( p_tmp_table in varchar2 default 'TMP_RESULT' )
is
vcounter pls_integer;
vsql clob;
vtimestamp date; -- or timestamp
begin
-- create table to store results
select count(*) into vcounter from all_tables where table_name = upper(p_tmp_table) and owner = 'MY_SCHEMA';
if vcounter = 1
then
execute immediate ' drop table '||p_tmp_table||' purge ' ;
end if;
vsql := ' create table '||p_tmp_table||'
( table_name varchar2(128) ,
id number,
timestamp_modify date -- or timestamp
) ';
execute immediate vsql ;
-- Populate rows
for h in
( select a.table_name from all_tables a
where a.owner = 'MY_SCHEMA'
and a.table_name in ( select distinct b.table_name from all_tab_columns b where b.owner = 'MY_SCHEMA'
and b.column_name = 'ID' and b.column_name = 'TIMESTAMP_MODIFY'
)
)
loop
vsql := ' insert into '||p_tmp_table||' ( table_name , id, timestamp_modify )
select '''||h.table_name||''' as table_name , id , timestamp_modify
from my_schema.'||h.table_name||'
' ;
execute immediate vsql ;
commit ;
end loop;
exception when others then raise;
end;
/

PL/SQL can you INSERT INTO (SELECT GROUP BY)?

I am tasked with creating an Oracle PL/SQL procedure "summarizer" that creates a summary table (mean, median etc. for each column) from a table.
The original table (mix of numeric and categorical columns):
column_1 | column_2| column_3| column_4
---------------------------------------
The desired output:
table_name | column_name | mean | tally
---------------------------------------
To do this, I am attempting to use a cursor that iterates over the USER_TAB_COLUMNS table (contains table_name, column_name) to INSERT the aggregations for each column_name INTO the SUMMARY_TABLE.
Here is my progress so far:
CREATE OR REPLACE PROCEDURE summarizer
IS
CURSOR column_cursor IS
SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE
FROM USER_TAB_COLUMNS
WHERE TABLE_NAME = 'BANK';
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE SUMMARY_TABLE';
EXECUTE IMMEDIATE 'CREATE TABLE SUMMARY_TABLE (
table_name VARCHAR(20),
column_name VARCHAR(20),
data_type VARCHAR(20),
mean NUMBER,
tally NUMBER,
PRIMARY KEY (table_name, column_name))';
FOR colname IN column_cursor LOOP
INSERT INTO SUMMARY_TABLE
SELECT
colname.table_name AS table_name,
colname.column_name AS column_name,
colname.data_type AS data_type,
mean(colname.column_name) AS mean,
count(colname.column_name) AS tally
FROM BANK
GROUP BY table_name, column_name, data_type;
END LOOP;
COMMIT;
END summarizer;
This produces the error:
Error report -
20/12 PL/SQL: SQL Statement ignored
28/51 PL/SQL: ORA-00904: "DATA_TYPE": invalid identifier
I am unable to locate the cause of this error. I believe it could be something to do with a GROUP BY in the INSERT INTO statement. Can anyone help?
You need dynamic SQL to use variables in a query string.
Consider:
FOR colname IN column_cursor LOOP
EXECUTE IMMEDIATE
'INSERT INTO SUMMARY_TABLE
SELECT
''' || colname.table_name || ''' AS table_name,
''' || colname.column_name || ''' AS column_name,
''' || colname.data_type || ''' AS data_type,
avg(' || colname.column_name || ') AS mean,
count(' || colname.column_name || ') AS tally
FROM BANK';
END LOOP;
Side notes:
the constant values (table name, column name and datatype) need to be enclosed in quotes
there is no mean() aggregate function in Oracle (nor in most other RDBMS): you can use avg() instead
you don't actually need a group by clause in your insert ... select ... query, since the non-aggregated columns are constants
Demo on DB Fiddle:
-- create the table and insert a few records
create table bank(id int, val int);
begin
insert into bank values(1, 1);
insert into bank values(2, 1);
insert into bank values(3, 1);
end;
/
-- create the summary table (it must exist since the procedure drops it)
create table summary_table(id int);
-- create the procedure
CREATE OR REPLACE PROCEDURE summarizer
IS
CURSOR column_cursor IS
SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE
FROM USER_TAB_COLUMNS
WHERE TABLE_NAME = 'BANK';
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE SUMMARY_TABLE';
EXECUTE IMMEDIATE 'CREATE TABLE SUMMARY_TABLE (
table_name VARCHAR(20),
column_name VARCHAR(20),
data_type VARCHAR(20),
mean NUMBER,
tally NUMBER,
PRIMARY KEY (table_name, column_name))';
FOR colname IN column_cursor LOOP
EXECUTE IMMEDIATE
'INSERT INTO SUMMARY_TABLE
SELECT
''' || colname.table_name || ''' AS table_name,
''' || colname.column_name || ''' AS column_name,
''' || colname.data_type || ''' AS data_type,
avg(' || colname.column_name || ') AS mean,
count(' || colname.column_name || ') AS tally
FROM BANK';
END LOOP;
COMMIT;
END summarizer;
/
-- run the procedure
begin
summarizer;
end;
/
-- check the results
select * from summary_table
TABLE_NAME | COLUMN_NAME | DATA_TYPE | MEAN | TALLY
:--------- | :---------- | :-------- | ---: | ----:
BANK | ID | NUMBER | 2 | 3
BANK | VAL | NUMBER | 1 | 3

Oracle get table names based on column value

I have table like this:
Table-1
Table-2
Table-3
Table-4
Table-5
each table is having many columns and one of the column name is employee_id.
Now, I want to write a query which will
1) return all the tables which is having this columns and
2) results should show the tables if the column is having values or empty values by passing employee_id.
e.g. show table name, column name from Table-1, Table-2,Table-3,... where employee_id='1234'.
If one of the table doesn't have this column, then it is not required to show.
I have verified with link, but it shows only table name and column name and not by passing some column values to it.
Also verified this, but here verifies from entire schema which I dont want to do it.
UPDATE:
Found a solution, but by using xmlsequence which is deprecated,
1)how do I make this code as xmltable?
2) If there are no values in the table, then output should have empty/null. or default as "YES" value
WITH char_cols AS
(SELECT /*+materialize */ table_name, column_name
FROM cols
WHERE data_type IN ('CHAR', 'VARCHAR2') and table_name in ('Table-1','Table-2','Table-3','Table-4','Table-5'))
SELECT DISTINCT SUBSTR (:val, 1, 11) "Employee_ID",
SUBSTR (table_name, 1, 14) "Table",
SUBSTR (column_name, 1, 14) "Column"
FROM char_cols,
TABLE (xmlsequence (dbms_xmlgen.getxmltype ('select "'
|| column_name
|| '" from "'
|| table_name
|| '" where upper("'
|| column_name
|| '") like upper(''%'
|| :val
|| '%'')' ).extract ('ROWSET/ROW/*') ) ) t ORDER BY "Table"
/
This query can be done in one step using the (non-deprecated) XMLTABLE.
Sample Schema
--Table-1 and Table-2 match the criteria.
--Table-3 has the right column but not the right value.
--Table-4 does not have the right column.
create table "Table-1" as select '1234' employee_id from dual;
create table "Table-2" as select '1234' employee_id from dual;
create table "Table-3" as select '4321' employee_id from dual;
create table "Table-4" as select 1 id from dual;
Query
--All tables with the column EMPLOYEE_ID, and the number of rows where EMPLOYEE_ID = '1234'.
select table_name, total
from
(
--Get XML results of dynamic query on relevant tables and columns.
select
dbms_xmlgen.getXMLType(
(
--Create a SELECT statement on each table, UNION ALL'ed together.
select listagg(
'select '''||table_name||''' table_name, count(*) total
from "'||table_name||'" where employee_id = ''1234'''
,' union all'||chr(10)) within group (order by table_name) v_sql
from user_tab_columns
where column_name = 'EMPLOYEE_ID'
)
) xml
from dual
) x
cross join
--Convert the XML data to relational.
xmltable('/ROWSET/ROW'
passing x.xml
columns
table_name varchar2(128) path 'TABLE_NAME',
total number path 'TOTAL'
);
Results
TABLE_NAME TOTAL
---------- -----
Table-1 1
Table-2 1
Table-3 0
Just try to use code below.
Pay your attention that may be nessecery clarify scheme name in loop.
This code works for my local db.
set serveroutput on;
DECLARE
ex_query VARCHAR(300);
num NUMBER;
emp_id number;
BEGIN
emp_id := <put your value>;
FOR rec IN
(SELECT table_name
FROM all_tab_columns
WHERE column_name LIKE upper('employee_id')
)
LOOP
num :=0;
ex_query := 'select count(*) from ' || rec.table_name || ' where employee_id = ' || emp_id;
EXECUTE IMMEDIATE ex_query into num;
if (num>0) then
DBMS_OUTPUT.PUT_LINE(rec.table_name);
end if;
END LOOP;
END;
I tried with the xml thing, but I get an error I cannot solve. Something about a zero size result. How difficult is it to solve this instead of raising exception?! Ask Oracle.
Anyway.
What you can do is use the COLS table to know what table has the employee_id column.
1) what table from table TABLE_LIKE_THIS (I assume column with table names is C) has this column?
select *
from COLS, TABLE_LIKE_THIS t
where cols.table_name = t
and cols.column_name = 'EMPLOYEE_ID'
-- think Oracle metadata/ think upper case
2) Which one has the value you are looking for: write a little chunk of Dynamic PL/SQL with EXECUTE IMMEDIATE to count the tables matching above condition
declare
v_id varchar2(10) := 'JP1829'; -- value you are looking for
v_col varchar2(20) := 'EMPLOYEE_ID'; -- column
n_c number := 0;
begin
for x in (
select table_name
from all_tab_columns cols
, TABLE_LIKE_THIS t
where cols.table_name = t.c
and cols.column_name = v_col
) loop
EXECUTE IMMEDIATE
'select count(1) from '||x.table_name
||' where Nvl('||v_col||', ''##'') = ''' ||v_id||'''' -- adding quotes around string is a little specific
INTO n_c;
if n_c > 0 then
dbms_output.put_line(n_C|| ' in ' ||x.table_name||' has '||v_col||'='||v_id);
end if;
-- idem for null values
-- ... ||' where '||v_col||' is null '
-- or
-- ... ||' where Nvl('||v_col||', ''##'') = ''##'' '
end loop;
dbms_output.put_line('done.');
end;
/
Hope this helps

Need help on writing sql query with dynamic columns

I have to write a query which does below. I tried but couldn't write. Please help me.
I have table which returns below result set.
select *
from table1; --(rowid and ColumnName are columns of the table)
Output:
rowid ColumnName
------------------------------
1 Segment1
2 Segment2
I have another table which has below structure : (Segment1 and Segment2 are columns here)
select *
from table2;
Output:
appId Segment1 Segment2 Segment3
---------------------------------------------
a1 fld1 fld2 per
a2 cmp1 hcd4 klp
I need to write a query, which reads the "ColumnName" values from first table and retrieves column values in the second table.
That means, from the table1, I will know what are the available columns I the table2 and from table2, I will know what is the data stored against those columns.
Please let me know if I am not clear.
This query is in Oracle SQL
As mentioned in the comment you need a PLSQL block with dynamic sql. See below an example:
Tables:
create table table1 (row_id number,
ColumnName varchar2(100))
create table table2 (appId number,
Segment1 varchar2(100),
Segment2 varchar2(100),
Segment3 varchar2(100));
Insert all
into TABLE1 (ROW_ID, COLUMNNAME) Values (1, 'Segment1')
into TABLE1 (ROW_ID, COLUMNNAME) Values (2, 'Segment2')
into TABLE2 (APPID, SEGMENT1, SEGMENT2, SEGMENT3) Values (1, 'RRR', 'KKK', 'MMM')
into TABLE2 (APPID, SEGMENT1, SEGMENT2, SEGMENT3) Values (2, 'ZZZ', 'PPP', 'QQQ')
into TABLE2 (APPID, SEGMENT1, SEGMENT2, SEGMENT3) Values (3, 'LLL', 'NNN', 'DDD')
select * from dual;
Code:
DECLARE
var VARCHAR2 (1000);
v_sql VARCHAR2 (2000);
TYPE x_var IS TABLE OF VARCHAR2(1000);
z_var x_var;
num number:=0;
BEGIN
FOR rec IN ( SELECT DISTINCT columnname
FROM table1
ORDER BY 1)
LOOP
num := num +1;
if num = 1 then
var:= rec.columnname;
else
var := var || ' || '' , ''||' || rec.columnname;
end if;
END LOOP;
var := RTRIM (LTRIM (var, ','), ',');
v_sql := 'select '|| var ||' from table2';
EXECUTE IMMEDIATE v_sql BULK COLLECT INTO z_var;
FOR i IN 1 .. z_var.COUNT
LOOP
DBMS_OUTPUT.put_line (z_var(i));
END LOOP;
END;
Output:
SQL> /
RRR , KKK
ZZZ , PPP
LLL , NNN
Dynamic columns in a SQL statement are almost always a bad idea. There's usually a way to avoid these kind of problems and build a simpler solution.
But if this is one of those rare times when you really need to run dynamic SQL in SQL then you'll need to install and run something like my open source project Method4.
For example:
create table table1 as
select 1 id, 'Segment1' columnName from dual union all
select 2 id, 'Segment2' columnName from dual;
create table table2 as
select 'a1' appId, 'fld1' Segment1, 'fld2' Segment2, 'per' Segment3 from dual union all
select 'a2' appId, 'cmp1' Segment1, 'hcd4' Segment2, 'klp' Segment3 from dual;
select * from table(method4.dynamic_query(
q'[
select
'select appID, '
||listagg(columnName, ',') within group (order by id)
||' from table2'
sql_statement
from table1
]'
));
APPID SEGMENT1 SEGMENT2
----- -------- --------
a1 fld1 fld2
a2 cmp1 hcd4
There are a lot of downsides to running this way. The code is complicated, slow, and has some odd behavior. For an explanation of how this works, see this article
by Adrian Billington.
Will the below PL SQL block help your requirement.
BEGIN
FOR iter IN (
SELECT column_name
FROM all_tab_columns
WHERE upper(table_name) = 'table1'
AND UPPER(column_name) LIKE 'SEGMENT%'
)
LOOP
SELECT iter.column_name INTO temp_table FROM table1
dbms_output.put_line(temp_table.column_name);
END LOOP;
END;
/
Say you have tables like the following:
SQL> select * from someTable;
COLUMN1 COLUMN2 COLUMN3
---------- ---------- ----------
1 2 3
2 4 6
3 6 9
SQL> select * from tableOfColumns;
COLUMNN
-------
column1
column3
You may need something like the following:
SQL> declare
2 type tListOfResults is table of varchar2(1000);
3 vSQL varchar2(1000);
4 vResult tListOfResults ;
5 begin
6 select 'select ' || listagg (columnName, ' || '', '' || ') within group (order by columnName) || ' from someTable'
7 into vSQL
8 from tableOfColumns;
9 --
10 execute immediate vSQL bulk collect into vResult;
11 if vResult.count() > 0 then
12 for i in vResult.first .. vResult.last loop
13 dbms_output.put_line(vResult(i));
14 end loop;
15 end if;
16 end;
17 /
1, 3
2, 6
3, 9
PL/SQL procedure successfully completed.

How to select a column from all tables in which it resides?

I have many tables that have the same column 'customer_number'.
I can get a list of all these table by query:
SELECT table_name FROM ALL_TAB_COLUMNS
WHERE COLUMN_NAME = 'customer_number';
The question is how do I get all the records that have a specific customer number from all these tables without running the same query against each of them.
To get record from a table, you have write a query against that table. So, you can't get ALL the records from tables with specified field without a query against each one of these tables.
If there is a subset of columns that you are interested in and this subset is shared among all tables, you may use UNION/UNION ALL operation like this:
select * from (
select customer_number, phone, address from table1
union all
select customer_number, phone, address from table2
union all
select customer_number, phone, address from table3
)
where customer_number = 'my number'
Or, in simple case where you just want to know what tables have records about particular client
select * from (
select 'table1' src_tbl, customer_number from table1
union all
select 'table2', customer_number from table2
union all
select 'table3', customer_number from table3
)
where customer_number = 'my number'
Otherwise you have to query each table separatelly.
DBMS_XMLGEN enables you to run dynamic SQL statements without custom PL/SQL.
Sample Schema
create table table1(customer_number number, a number, b number);
insert into table1 values(1,1,1);
create table table2(customer_number number, a number, c number);
insert into table2 values(2,2,2);
create table table3(a number, b number, c number);
insert into table3 values(3,3,3);
Query
--Get CUSTOMER_NUMBER and A from all tables with the column CUSTOMER_NUMBER.
--
--Convert XML to columns.
select
table_name,
to_number(extractvalue(xml, '/ROWSET/ROW/CUSTOMER_NUMBER')) customer_number,
to_number(extractvalue(xml, '/ROWSET/ROW/A')) a
from
(
--Get results as XML.
select table_name,
xmltype(dbms_xmlgen.getxml(
'select customer_number, a from '||table_name
)) xml
from user_tab_columns
where column_name = 'CUSTOMER_NUMBER'
);
TABLE_NAME CUSTOMER_NUMBER A
---------- --------------- -
TABLE1 1 1
TABLE2 2 2
Warnings
These overly generic solutions often have issues. They won't perform as well as a plain old SQL statements and they are more likely to run into bugs. In general, these types of solutions should be avoided for production code. But they are still very useful for ad hoc queries.
Also, this solution assumes that you want the same columns from each row. If each row is different then things get much more complicated and you may need to look into technologies like ANYDATASET.
I assume you want to automate this. Two approaches.
SQL to generate SQL scripts
.
spool run_rep.sql
set head off pages 0 lines 200 trimspool on feedback off
SELECT 'prompt ' || table_name || chr(10) ||
'select ''' || table_name ||
''' tname, CUSTOMER_NUMBER from ' || table_name || ';' cmd
FROM all_tab_columns
WHERE column_name = 'CUSTOMER_NUMBER';
spool off
# run_rep.sql
PLSQL
Similar idea to use dynamic sql:
DECLARE
TYPE rcType IS REF CURSOR;
rc rcType;
CURSOR c1 IS SELECT table_name FROM all_table_columns WHERE column_name = 'CUST_NUM';
cmd VARCHAR2(4000);
cNum NUMBER;
BEGIN
FOR r1 IN c1 LOOP
cmd := 'SELECT cust_num FROM ' || r1.table_name ;
OPEN rc FOR cmd;
LOOP
FETCH rc INTO cNum;
EXIT WHEN rc%NOTFOUND;
-- Prob best to INSERT this into a temp table and then
-- select * that to avoind DBMS_OUTPUT buffer full issues
DBMS_OUTPUT.PUT_LINE ( 'T:' || r1.table_name || ' C: ' || rc.cust_num );
END LOOP;
CLOSE rc;
END LOOP;
END;