pl/sql get all structure tables on oracle - oracle

I have problem about how to get all of list structure table using loop pl/sql,
i have syntax loop like bellow :
BEGIN
FOR x IN (SELECT table_name FROM user_tables)
LOOP
EXECUTE IMMEDIATE 'DESC' || x.table_name;
END LOOP;
COMMIT;
END;
and this is log output from sql developer
Error starting at line 14 in command:
BEGIN
FOR x IN (SELECT table_name FROM user_tables)
LOOP
EXECUTE IMMEDIATE 'DESC' || x.table_name;
END LOOP;
COMMIT;
END;
Error report:
ORA-00900: invalid SQL statement
ORA-06512: at line 4
00900. 00000 - "invalid SQL statement"
*Cause:
*Action:
Help me to solve this
Thanks

The DESC command is neither SQL nor plsql but a sqlplus command, so you can't use it in a plsql code.
More than that, why ? you can get all the values you need from USER_TAB_COLUMNS ...
Use DBMS_OUTPUT.put_line() instead:
BEGIN
FOR x IN (SELECT COLUMN_NAME, DATA_TYPE, NULLABLE FROM USER_TAB_COLUMNS)
LOOP
DBMS_OUTPUT.put_line(COLUMN_NAME || ' ' || DATA_TYPE || ' ' || NULLABLE );
END LOOP;
COMMIT;
END;
Of course this can be formatted nicer and there are more columns you can select ...

Consider this instead:
Select * from All_tab_Cols
or to be closer to what is returned from describe:
Select Owner, Table_name, ColumN_Name, Data_Type, Data_Length, Nullable
from all_tab_Cols;
To address your specific problem shouldn't it be:
EXECUTE IMMEDIATE 'DESC ' || x.table_name|| ';';
Missing space between desc & table name and ; is part of the SQL to run isn't it?

If you're trying to reverse engineer the schema then use the DBMS_Metadata package to do so, as it can also extract constraints, privileges, users etc.

Related

dbms_out returning column 1: PLS-00428: an INTO clause is expected in SELECT statement

Running this query in sql-developer :
SET SERVEROUTPUT ON
BEGIN
DBMS_OUTPUT.PUT_LINE ('schema > table > key ');
SELECT 'table_name' TABLE_NAME , t.* FROM table_name t ;
END ;
I get this message :
Error report -
ORA-06550: line 4, column 1: PLS-00428: an INTO clause is expected in
this SELECT statement
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
while when I run the two statements one by one it works fine.
so why do I get the error and how to avoid it ?
many thanks,
You're confusing SQL and PL/SQL statements, as explained in comments. You can select into something, but you'd either get a single row of data, or select into a collection and then iterate over that manually, as Aramillo showed.
You can use a 'cursor for-loop' to iterate over your rows instead:
SET SERVEROUTPUT ON
BEGIN
DBMS_OUTPUT.PUT_LINE ('schema > table > key ');
FOR rec IN (SELECT 'table_name' TABLE_NAME , t.* FROM table_name t)
LOOP
DBMS_OUTPUT.PUT_LINE (rec.COLUMN_NAME1||','||rec.COLUMN_NAME2);
END LOOP;
END;
/
But given your starting point it's simpler to leave the query as plan SQL and run it after the block:
SET SERVEROUTPUT ON
BEGIN
DBMS_OUTPUT.PUT_LINE ('schema > table > key ');
END;
/
SELECT 'table_name' TABLE_NAME , t.* FROM table_name t;
or in SQL*Plus or SQL Developer, use the client prompt command instead of dbms_output:
prompt schema > table > key
SELECT 'table_name' TABLE_NAME , t.* FROM table_name t;
For example, if you want to print columns COLUMN_NAME of your table, you can do somthing like this:
DECLARE
TYPE TABLE_OBJ IS TABLE OF TABLE_NAME%ROWTYPE;
TABLE_T TABLE_OBJ;
BEGIN
SELECT * BULK COLLECT INTO TABLE_T FROM TABLE_NAME;
FOR i IN 1..TABLE_T.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(TABLE_T(i).COLUMN_NAME1||','||TABLE_T(i).COLUMN_NAME2);
END LOOP;
END;

updating values in a loop by column name

I have a table with several columns, and I would like to eliminate spaces value (' ') from the values. The query is:
update table
set column_name = trim(both ' ' from column_name)
where column_name like '% '
and since the table contains around 55 columns so probably a loop would be a feasible idea instead of writing update statement for each and every column.
First I checked if looping is working:
declare
column_name varchar2(2048);
cursor pointer is
select column_name into column_name from user_tab_cols where table_name = 'TABLE_NAME';
begin
for x in pointer
loop
dbms_output.put_line(x.column_name);
end loop;
end;
yes, it is working. I get column names in dbms_output window.
Now,
Here is what I am trying to do which doesn't seem to work:
declare
column_var varchar2(2048);
cursor pointer is
select column_name into column_var from user_tab_cols where table_name = 'TABLE_NAME';
begin
for x in pointer
loop
update table_name
set x.column_var = trim(both ' ' from x.column_var)
where x.column_var like '% ';
commit;
end loop;
end;
This is, unfortunately not working. This is error I get:
ORA-06550: line 11, column 18:
PLS-00302: component 'COLUMN_VAR' must be declared.
ORA-06550: line 11, column 16:
PL/SQL: ORA-00904: "X"."COLUMN_VAR": invalid identifier
ORA-06550: line 9, column 10:
PL/SQL: SQL Statement ignored
Any idea where I am going off the track?
Thanks in advance :-)
I think you need to provide the actual column name, rather than the string representing the column name in the statement. Would an execute immediate work for you?
declare
column_var varchar2(2048);
cursor pointer is
select column_name into column_var from user_tab_cols where table_name = 'TABLE_NAME';
begin
for x in pointer
loop
execute immediate
'update table_name ' ||
'set '|| x.column_var ||' = trim(both '' '' from '|| x.column_var ||')'||
'where '|| x.column_var ||' like ''% ''';
commit;
end loop;
end;
You need to use dynamic sql for this
BEGIN
FOR t IN (select column_name from user_tab_cols where table_name = 'MyTable')
LOOP
EXECUTE IMMEDIATE
'update MyTable set '||t.column_name||' = trim(both '' '' from '||t.column_name||') where '||t.column_name||' like ''% ''';
END LOOP;
END;
/

Looping through tables with Oracle Subqueries

I want to run an Oracle validation function against every table in the database that has a suitable column.
The validation can be run against one table simply:
SELECT
count (*)
FROM
Table_name t
Where
SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT(t.Column_name, 0.005) <> 'TRUE';
This works fine for an individual table, but as there are over 100 to test I wanted to merge it with the Oracle Metadata table using a subquery and thus automate the whole thing. I've come up with two variants but neither works, I guess because it's having trouble passing variables from inside the subquery.
My two attempts are:
SELECT TABLE_NAME tab, COLUMN_NAME col, (select count(*) from tab where sdo_geom.validate_geometry(tab.col, 0.005) <> 'TRUE')
From
All_Tab_Columns
where
owner = 'WCCDATA' and DATA_TYPE = 'SDO_GEOMETRY'
Which returns:
SQL Error: ORA-00904: "TAB"."COL": invalid identifier
00904. 00000 - "%s: invalid identifier"
and
SELECT count(*)
From
(SELECT
TABLE_NAME, COLUMN_NAME as col
FROM
All_Tab_Columns
where
owner = 'WCCDATA' and DATA_TYPE = 'SDO_GEOMETRY') subquery
WHERE sdo_geom.validate_geometry(subquery.col, 0.005) <> 'TRUE';
which returns:
ORA-06512: at "MDSYS.SDO_GEOM", line 2204
00942. 00000 - "table or view does not exist"
Anyone have any thoughts? Thanks.
You can't ever reference column values as identifiers (tables, columns, etc.). In order to do this, you'll need to write some PL/SQL to create and execute the SQL dynamically, perhaps like this:
DECLARE
CURSOR cur_tables IS
SELECT table_name,
'SELECT count(*) From '
|| table_name
|| ' WHERE sdo_geom.validate_geometry('
|| column_name
|| ', 0.005) <> ''TRUE'''
AS dsql
FROM all_tab_columns
WHERE owner = 'WCCDATA' AND data_type = 'SDO_GEOMETRY';
v_count NUMBER;
BEGIN
FOR r_tables IN cur_tables LOOP
EXECUTE IMMEDIATE r_tables.dsql INTO v_count;
DBMS_OUTPUT.put_line(r_tables.table_name || ': ' || v_count);
END LOOP;
END;

Execute For Each Table in PLSQL

I want to the the number of records in all tables that match a specific name criteria. Here is the SQL I built
Declare SQLStatement VARCHAR (8000) :='';
BEGIN
SELECT 'SELECT COUNT (*) FROM ' || Table_Name || ';'
INTO SQLStatement
FROM All_Tables
WHERE 1=1
AND UPPER (Table_Name) LIKE UPPER ('MSRS%');
IF SQLStatement <> '' THEN
EXECUTE IMMEDIATE SQLStatement;
END IF;
END;
/
But I get the following error:
Error at line 1
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at line 3
Script Terminated on line 1.
How do I modify this so that it runs for all matching tables?
Update:
Based on an answer received, I tried the following but I do not get anything in the DBMS_OUTPUT
declare
cnt number;
begin
for r in (select table_name from all_tables) loop
dbms_output.put_line('select count(*) from CDR.' || r.table_name);
end loop;
end;
/
declare
cnt number;
begin
for r in (select owner, table_name from all_tables
where upper(table_name) like ('%MSRS%')) loop
execute immediate 'select count(*) from "'
|| r.owner || '"."'
|| r.table_name || '"'
into cnt;
dbms_output.put_line(r.owner || '.' || r.table_name || ': ' || cnt);
end loop;
end;
/
If you're selecting from all_tables you cannot count on having been given the grants necessary to select from the table name. You should therefore check for the ORA-00942: table or view does not exist error thrown.
As to the cause for your error: You get this error because the select statement returns a result set with more than one row (one for each table) and you cannot assign such a result set to a varchar2.
By the way, make sure you enable dbms_output with SET SERVEROUT ON before executing this block.

Go over all columns in tables in Oracle

This is a noobie question, most likely syntax one. But I am kinda lost...
I need to go over all columns in all tables in Oracle to generate trigger script. That trigger should insert the row being updated to a log table which is nearly the same as the original table. I thought I would just go over all the columns and just concatenate strings. Fairly easy but I am struggling with the syntax...
Here's what I have so far:
DECLARE
cursor tableNames is
select table_name
from user_tables
where table_name not like '%_A';
lSql varchar2(3000);
type t_columnRow is ref cursor;
v_columns t_columnRow;
begin
FOR tableName in tableNames
LOOP
open v_columns for select COLUMN_NAME from user_tab_columns where table_name = tableName;
for columnRow in v_columns LOOP
DBMS_OUTPUT.PUT_LINE(tableName || '.' || columnRow.COLUMN_NAME);
-- Here I would just concatenate the strings ....
END LOOP;
END LOOP;
End;
For that I am getting the following error:
Error at line 1
ORA-06550: line 14, column 84:
PLS-00382: expression is of wrong type
ORA-06550: line 16, column 22:
PLS-00221: 'V_COLUMNS' is not a procedure or is undefined
ORA-06550: line 16, column 5:
PL/SQL: Statement ignored
Try this:
BEGIN
FOR t IN (SELECT table_name FROM user_tables WHERE table_name not like '%_A')
LOOP
FOR c IN (SELECT column_name FROM user_tab_columns WHERE table_name = t.table_name)
LOOP
DBMS_OUTPUT.PUT_LINE(t.table_name||'.'||c.column_name);
-- Here I would just concatenate the strings ....
END LOOP;
END LOOP;
END;
You may be able to get away with something as simple as this:
DECLARE
cursor tableNames is
select table_name
from user_tables
where table_name not like '%_A';
lSql varchar2(3000);
begin
FOR tableName in tableNames
LOOP
for columnRow in (select COLUMN_NAME from user_tab_columns where table_name = tableName) LOOP
DBMS_OUTPUT.PUT_LINE(tableName || '.' || columnRow.COLUMN_NAME);
-- Here I would just concatenate the strings ....
END LOOP;
END LOOP;
End;

Resources