table name in loop oracle pl/sql - oracle

declare
v_cnt NUMBER;
C SYS_REFCURSOR;
TMP_TBL_NM VARCHAR2(100);
stmt VARCHAR2(1000);
the_name varchar2 (50);
cursor c_table is
(SELECT a.table_name
--, a.column_name, a.constraint_name, c.owner,
--c.r_owner , c_pk.table_name r_table_name, c_pk.constraint_name r_pk
FROM all_cons_columns a
JOIN all_constraints c ON a.owner = c.owner AND a.constraint_name = c.constraint_name
JOIN all_constraints c_pk ON c.r_owner = c_pk.owner AND c.r_constraint_name = c_pk.constraint_name
WHERE c.owner like '%LTR' and c_pk.table_name like '%EnumerationValue%');
begin
stmt := 'SELECT table_name FROM ' || TMP_TBL_NM || ' ORDER BY 1';
OPEN C FOR stmt;
for t in C
loop
FETCH C INTO the_name;
EXIT WHEN C%NOTFOUND;
--my query for each table goes here
end loop;
end;
i want to use table names in loop as to check the records as per my query.
it is giving me error only by getting table name in the loop.
how can i get table name in a loop so that i can fetch rows as per my requirement from each table in a loop.
thanks in advance.

I'm not entirely sure what you want to achieve here, but if it's just the table names you're interested in, you can make your code a lot less complicated doing it this way:
declare
cursor c_table is
SELECT a.table_name
--, a.column_name, a.constraint_name, c.owner,
--c.r_owner , c_pk.table_name r_table_name, c_pk.constraint_name r_pk
FROM all_cons_columns a
JOIN all_constraints c ON a.owner = c.owner AND a.constraint_name = c.constraint_name
JOIN all_constraints c_pk ON c.r_owner = c_pk.owner AND c.r_constraint_name = c_pk.constraint_name
begin
for t in c_table loop
--do something with the table name
dbms_output.put_line(t.table_name);
end loop;
end;
This kind of for loop also handles the opening and closing of the cursor and is the recommended way to do these kind of operations.

Related

Is there a way to make a PLSQL script that lists all columns that IS NULL for every record in a table?

I am working with a huge database with several columns and records. I want to browse a specific table and make a list of the columns that are empty for every record.
Is this possible without refering to all the specific column names?
Thanks for help!
It's possible but if you have a lot data it will last a long time.
create table xxx as select * from dba_objects where rownum < 10000;
prepare test table get table stats. It can be long lasting process.
begin
dbms_stats.gather_table_stats(user,'XXX',estimate_percent =>100);
-- ..
-- others tables to analizye
end;
Generate reports.
select table_name,column_name from user_tab_cols where coalesce(low_value,high_value) is null and table_name in('XXX');
You can use the below script to find out the null columns in your database -
DECLARE
COUNT_COL INT;
SQL_STR VARCHAR2(100);
BEGIN
FOR I IN (SELECT OBJECT_NAME, COLUMN_NAME
FROM USER_OBJECTS UO
JOIN USER_TAB_COLS UTC ON UO.OBJECT_NAME = UTC.TABLE_NAME) LOOP
SQL_STR := 'SELECT COUNT(1) FROM ' || I.OBJECT_NAME || ' WHERE ' || i.COLUMN_NAME || ' IS NOT NULL';
EXECUTE IMMEDIATE SQL_STR INTO COUNT_COL;
IF COUNT_COL = 0 THEN
DBMS_OUTPUT.PUT_LINE(I.COLUMN_NAME);
END IF;
END LOOP;
END;
Here is the fiddle.
Try for all record in table:
SELECT a.owner, a.table_name, b.column_name
FROM all_tables a, all_tab_columns b
WHERE a.table_name = '<TABLE_NAME>'
AND a.table_name = b.table_name
AND a.num_rows = b.num_nulls
For all table
SELECT a.owner, a.table_name, b.column_name
FROM all_tables a, all_tab_columns b
WHERE a.table_name = b.table_name
AND a.num_rows = b.num_nulls

Oracle PL/SQL Swapping a for loop for dynamic SQL, assistance with syntax changes

I have a for loop, here:
BEGIN
for rws in (
select /*+parallel (4)*/ a.owner,a.table_name, round(sum(b.sum_bytes),2) TOT_OBJECT_SIZE_MB, EST_ONE_ROW_MB
from dba_tables#DB1 a, MV_PRD_SEG_DATA b
where a.table_name = b.segment_name
and a.table_name in
(select table_name from MV_PDU_TABLE where driver_table is null)
and a.owner in (select distinct productionschema from MV_PDU_TABLE c)
group by a.owner,a.table_name
order by a.table_name
)
loop
Data is pulled out of the loop as follows by referencing rws. :
execute immediate' select /*+parallel (4)*/ count(*) from ' ||rws.owner||'.'||rws.table_name || '#' || dblink into TOTAL_ROW_COUNT;
I now have to change some of the hard coded table references in the select statement to variables. (I will be declaring these earlier in the code.)
As I understand it, I must now switch to dynamic SQL.
In doing so, you can see here how the hard coded tables are now referred to as variables:
BEGIN
v_sql1 := 'select /*+parallel (4)*/ a.owner,a.table_name, round(sum(b.sum_bytes),2) TOT_OBJECT_SIZE_MB, EST_ONE_ROW_MB
from dba_tables#NAB1 a, '|| v_Mv_name ||' b
where a.table_name = b.segment_name
and a.table_name in
(select table_name from '|| v_Mv_name ||' where driver_table is null)
and a.owner in (select distinct productionschema from '|| v_Mv_name ||' c)
group by a.owner,a.table_name
order by a.table_name';
The issue is... how do I now manage getting the data out of the loop? I think I would loop, just using the variable containing the SQL?:
for rws in (v_sql1)
loop
If so, what would now go here?
execute immediate' select /*+parallel (4)*/ count(*) from ' <NO_IDEA_HOW_TO_REFERENCE_THE_DATA_IN_THE_LOOP_NOW> ' into TOTAL_ROW_COUNT;
You can also use a RefCursor:
declare
cur SYS_REFCURSOR;
owner varchar2(30);
table_namevarchar2(30);
TOT_OBJECT_SIZE_MB number;
EST_ONE_ROW_MB number;
TOTAL_ROW_COUNT integer;
v_sql1 varchar2(10000);
begin
v_sql1 := 'select /*+parallel (4)*/ a.owner,a.table_name, round(sum(b.sum_bytes),2) TOT_OBJECT_SIZE_MB, EST_ONE_ROW_MB
from dba_tables#NAB1 a, '|| v_Mv_name ||' b
where a.table_name = b.segment_name
and a.table_name in
(select table_name from '|| v_Mv_name ||' where driver_table is null)
and a.owner in (select distinct productionschema from '|| v_Mv_name ||' c)
group by a.owner,a.table_name
order by a.table_name';
open cur for v_sql1;
loop
fetch cur into owner, table_name, TOT_OBJECT_SIZE_MB, EST_ONE_ROW_MB;
exit when cur%NOTFOUND;
execute immediate' select /*+parallel (4)*/ count(*) from '||table_name into TOTAL_ROW_COUNT;
end loop;
end;
Usually a BULK COLLECT provides better performance. However, as you run a dedicated query for each record I don't think you will notice any difference in the performance.
You may do a BULK COLLECT into collection of record you wish to return and then loop through the collection.
You may be able to use this example readily into your script.
DECLARE
TYPE sizerec is RECORD ( owner dba_tables.owner%type,
table_name dba_tables.table_name%type,
tot_object_size_mb number);
TYPE srectab is TABLE OF sizerec;
srec srectab;
l_tab_name varchar2(40) := 'dba_tables';
BEGIN
EXECUTE IMMEDIATE
'SELECT a.owner,a.table_name,round(SUM(b.bytes),2) tot_object_size_mb
FROM '||l_tab_name||' a
JOIN dba_segments b ON a.table_name = b.segment_name where rownum < 10
GROUP BY a.owner,a.table_name ' BULK COLLECT INTO srec;
for i in srec.first..srec.last
loop
dbms_output.put_line(srec(i).owner||','||srec(i).table_name
||','||srec(i).tot_object_size_mb);
end loop;
END;
/
Output
PL/SQL procedure successfully completed.
SYS,BOOTSTRAP$,65536
SYS,FILE$,65536
SYS,OBJERROR$,65536
SYS,UNDO$,65536
SYS,PROXY_DATA$,65536
SYS,OBJ$,10485760
SYS,PROXY_ROLE_DATA$,65536
SYS,OBJAUTH$,2097152
SYS,CON$,262144

How do I declare my select query in PL/SQL?

I want to declare a select query to use it in a trigger but I am a noob in sql in general :P Can somebody help me?
My code (example):
DECLARE Primary_Keys VARCHAR(20);
BEGIN
SELECT cons.constraint_type
FROM all_constraints cons, all_cons_columns cols
WHERE cols.owner = 'DAB_NAME'
AND cons.constraint_type = 'P'
AND cons.constraint_name = cols.constraint_name
AND cons.owner = cols.owner;
END;
You may use a PROCEDURE composed of BULK COLLECT with FORALL :
SQL> set serveroutput on;
SQL> CREATE OR REPLACE PROCEDURE pr_list_constraints(
i_owner IN all_cons_columns.owner%TYPE
)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Constraint Types for '||i_owner);
DBMS_OUTPUT.PUT_LINE('------------------------------- ');
FOR constraint_rec
IN (SELECT distinct cons.constraint_type
FROM all_constraints cons, all_cons_columns cols
WHERE cols.owner = i_owner --'DAB_NAME'
--AND cons.constraint_type = 'P'
AND cons.constraint_name = cols.constraint_name
AND cons.owner = cols.owner)
LOOP
DBMS_OUTPUT.PUT_LINE(constraint_rec.constraint_type);
END LOOP;
END;
/
SQL> var p_owner varchar2(50);
SQL> exec pr_list_constraints(:p_owner);
Constraint Types for DAB_NAME
-------------------------------
R
U
P
C
P.S. Using a DB trigger is irrelevant for such type of tasks.

No matching unique or primary key for this column-list while query user_index table

SELECT DISTINCT(UI.TABLE_NAME)
,UI_INDEX_NAME
FROM USER_INDEXES UI
INNER JOIN USER_TABLES UT ON UT_TABLE_NAME = UI.TABLE_NAME
INNER JOIN TMP ON TMP.TABLE_NAME = UI.TABLE_NAME
INNER JOIN USER_CONS_COLUMNS UC ON UC.TABLE_NAME = UI.TABLE_NAME
WHERE UT.IOT_TYPE IS NULL
AND UC.COLUMN_NAME IN (
'STAFF_ID'
,'STAFF_UNIQUE_ID'
)
AND UC.TABLE_NAME LIKE 'HR_%'
OR UC.TABLE_NAME = 'PAYROLL';
Above table query the list of indexes referring to the table that having PK as staff_id or staff_unique_id from the table name PAYROLL and HR_*. TMP is the table that maintain these list of table name, as I don't want it to search through entire USER_TABLE or USER_INDEX.
I have no issue when manually select it, however error encountered:
ORA-02270: no matching unique or primary key for this column-list
in PL/SQL while selecting the result and doing INDEX REBULD
The result return seem incorrect, many redundant INDEX_NAME that point to same table. I put a DISTINCT for UI.TABLE_NAME to solve the duplicate. But in PLSQL, i do not need to populate UI.TABLE_NAME, so how can the error come from?
--index rebuild
FOR r IN (....) LOOP
l_sql := 'ALTER INDEX '||r.index_name||' REBUILD';
EXECUTE IMMEDIATE l_sql;
END LOOP;
--disable constraint
FOR m IN (SELECT UC.CONSTRAINT_NAME ,UC.TABLE_NAME FROM USER_CONSTRAINTS UC
INNER JOIN TMP ON UC.TABLE_NAME = TMP.TABLE_NAME
WHERE UC.TABLE_NAME = TMP.TABLE_NAME AND UC.CONSTRAINT_TYPE IN
('R', 'C', 'U') AND UC.TABLE_NAME LIKE 'HR_%' OR UC.TABLE_NAME =
'PAYROLL') LOOP
l_sql := 'ALTER TABLE '||m.TABLE_NAME||' DISABLE CONSTRAINT
'||m.CONSTRAINT_NAME||' CASCADE';
EXECUTE IMMEDIATE l_sql;
END LOOP;
--enable constraint
FOR n IN (SELECT UC.CONSTRAINT_NAME ,UC.TABLE_NAME FROM USER_CONSTRAINTS UC
INNER JOIN TMP ON UC.TABLE_NAME = TMP.TABLE_NAME
WHERE UC.TABLE_NAME = TMP.TABLE_NAME AND UC.CONSTRAINT_TYPE IN
('R', 'C', 'U') AND UC.TABLE_NAME LIKE 'HR_%' OR UC.TABLE_NAME =
'PAYROLL') LOOP
l_sql := 'ALTER TABLE '||n.TABLE_NAME||' ENABLE CONSTRAINT
'||n.CONSTRAINT_NAME||'';
EXECUTE IMMEDIATE l_sql;
END LOOP;

Error while executing query stored in a variable within FOR loop in stored procedure

While running this prepared statement
DECLARE
BEGIN
-- Get the list of dependent tables and store it in a variable.
FOR cons IN (SELECT A.TABLE_NAME
FROM ALL_CONSTRAINTS A, ALL_CONSTRAINTS B
WHERE A.CONSTRAINT_TYPE = 'xxx'
AND A.R_CONSTRAINT_NAME = B.CONSTRAINT_NAME
AND A.R_OWNER = B.OWNER
AND B.TABLE_NAME = 'MY_TABLE'
AND B.OWNER = 'DBA')
LOOP
SET #querytext = CONCAT('SELECT * FROM ',cons.TABLE_NAME);
PREPARE stamquery FROM #querytext;
EXECUTE stamquery;
DEALLOCATE PREPARE stamquery;
END LOOP;
END;
I am getting the error stating:
Encountered the symbol "STAMQUERY" when expecting one of the following:
:= . ( # % ;
I am new with procedures but looks like this is the way to do it based on my research on the internet.
Please let me know what am I doing wrong..
The Syntax you are using for PL/SQL is not correct. It should be something like this.
DECLARE
querytext VARCHAR2(1000); --declare the variable to store query.
v_tab_count NUMBER;
BEGIN
-- Get the list of dependent tables and store it in a variable.
FOR cons IN
(
SELECT
A.TABLE_NAME
FROM
ALL_CONSTRAINTS A,
ALL_CONSTRAINTS B
WHERE
A.CONSTRAINT_TYPE = 'xxx'
AND A.R_CONSTRAINT_NAME = B.CONSTRAINT_NAME
AND A.R_OWNER = B.OWNER
AND B.TABLE_NAME = 'MY_TABLE'
AND B.OWNER = 'DBA'
)
LOOP
querytext := CONCAT('SELECT COUNT(*) FROM ',cons.TABLE_NAME);
EXECUTE IMMEDIATE querytext INTO v_tab_count ; --dynamicall execute the
-- select statement.
DBMS_OUTPUT.PUT_LINE( 'TABLE ' ||cons.TABLE_NAME||' COUNT '||v_tab_count);
-- Display the table name and its count of rows.
END LOOP;
END;

Resources