Oracle, For cicle with a dinamic table - oracle

Hy Guys,
i have a problem with a Cursor, i can't find a solution.
i would like to do a second loop like in the code, where i loop dynamically for the table found above but return that error PLS-00103: Encountered the symbol "LOOP".
i am starting with pl-sql.
Can you give me some suggestions for fix that problem?
thx, all.
CURSOR V_LIST_TABLES IS
SELECT
OBJECT_TYPE,
OWNER ||'.'|| OBJECT_NAME AS SCHEMA,
OBJECT_NAME
FROM DBA_OBJECTS U
WHERE OWNER = 'MYSCHEMA'
AND OBJECT_TYPE IN ('TABLE');
BEGIN
FOR INDX_CURSOR IN V_LIST_TABLES LOOP
IF INDX_CURSOR.OBJECT_NAME LIKE '%TEST%' THEN
FOR INDX_CURSOR_2 IN ('SELECT * FROM' || INDX_CURSOR.OBJECT_NAME) LOOP
NULL;
-- DO SOMETHINGS
END LOOP;
END IF;
END LOOP;

You're making this way more complex than it need be.
vsql varchar2(200);
vfname varchar2(20);
vlname varchar2(20);
vdob date;
For x in (select owner,
table_name
from dba_tables
where owner = 'MYSCHEMA'
and table_name like '%TEST%'
)
loop
-- do something with x.owner and x.table_name
vsql := 'select fname, lname, dob into vfname, vlname, vdob from '||
x.owner||'.'||x.table_name;
dbms_output.put_line(vsql); -- debug only
execute vsql;
end loop;

Related

error ORA-00998: must name this expression with a column alias

I tried to create table from all_tab_columns but it throws me an error.
like error ORA-00998: must name this expression with a column alias.
i tried to figure it out but not working.
Declare
CURSOR c1 IS
SELECT COLUMN_NAME FROM (select 'standard_hash(MY_NAME) AS MY_NAME' COLUMN_NAME from DUAL
UNION
SELECT COLUMN_NAME FROM ALL_TAB_COLUMNS WHERE TABLE_NAME='TABLE1' AND COLUMN_NAME<>'MY_NAME');
cols c1%ROWTYPE;
sqlstmt VARCHAR2(4000);
BEGIN
OPEN c1;
LOOP
FETCH c1 into cols;
EXIT WHEN c1%NOTFOUND;
sqlstmt := sqlstmt ||cols.column_name||',';
END LOOP;
CLOSE c1;
sqlstmt := 'CREATE TABLE TABLE2 AS SELECT '||substr(sqlstmt, 1, length(sqlstmt)-1)||' FROM TABLE1';
DBMS_OUTPUT.PUT_LINE(sqlstmt);
EXECUTE IMMEDIATE sqlstmt;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('error '||sqlerrm);
END;
/
You just have to give the name to the expression as follows:
sqlstmt := 'CREATE TABLE TABLE2 AS SELECT '
||substr(sqlstmt, 1, length(sqlstmt)-1)
||' as column_name FROM TABLE1'; -- column_name will bre name of the column of new table
As it will become the name of the column of newly created table.
I think this can be simplified somewhat.
You don't need to declare an explicit cursor and a record type and fetch each row into it, as this is already built into the language as the Cursor FOR loop construction:
declare
sqlStmt long := 'create table table2 as select ';
begin
for r in (
select 'standard_hash(my_name) as my_name' column_name
from dual
union
select column_name
from all_tab_columns
where table_name = 'TABLE1'
and column_name <> 'MY_NAME'
)
loop
sqlStmt := sqlStmt || r.column_name || ', ';
end loop;
sqlStmt := sqlStmt || rtrim(sqlStmt,', ') || ' from table1';
dbms_output.put_line(sqlStmt);
execute immediate sqlStmt;
end;
/
But you can do this without any loop, as the listagg function can already build a comma-separated list for you. It also makes it easier to retain the order of columns in the original table.
declare
selectList long;
sqlStmt long;
begin
select listagg(
case column_name
when 'MY_NAME' then 'standard_hash(my_name) as my_name'
else lower(column_name)
end, ', '
) within group (order by column_id) as select_list
into selectList
from user_tab_columns c
where c.table_name = 'TABLE1';
sqlStmt :=
'create table table2 pctfree 0 nologging parallel as '||chr(10)||
'select '||selectList||chr(10)||
'from table1';
dbms_output.put_line(sqlStmt||';');
execute immediate sqlstmt;
end;

Loop tables into pl/sql and display number of rows

I have loop for all the tables into db:
declare
V_TABL_NM ALL_TABLES.TABLE_NAME%TYPE;
BEGIN
FOR GET_TABL_LIST IN (SELECT TABLE_NAME FROM ALL_TABLES )LOOP
V_TABL_NM := GET_TABL_LIST.TABLE_NAME;
DBMS_OUTPUT.PUT_LINE(V_TABL_NM);
END LOOP;
END;
How can I sort my result and add number of records for each tables?
I try below but it does not work:
declare
V_TABL_NM ALL_TABLES.TABLE_NAME%TYPE;
table_row number;
BEGIN
FOR GET_TABL_LIST IN (SELECT TABLE_NAME FROM ALL_TABLES )LOOP
V_TABL_NM := GET_TABL_LIST.TABLE_NAME;
table_row: = select count(*) from TABLE_NAME;
DBMS_OUTPUT.PUT_LINE(V_TABL_NM, table_row);
END LOOP;
END;
You can not make a query that way; TABLE_NAME has no meaning there (and you're missing to use the cursor name), so you need to build a dynamic SQL and run it to put the value into a variable.
Besides, the PUT_LINE does not accept that parameters.
This should work:
DECLARE
table_row NUMBER;
BEGIN
FOR GET_TABL_LIST IN ( SELECT OWNER || '.' || TABLE_NAME AS TABLE_NAME
FROM ALL_TABLES
ORDER BY TABLE_NAME)
LOOP
EXECUTE IMMEDIATE 'select count(*) from ' || GET_TABL_LIST.TABLE_NAME INTO table_row;
DBMS_OUTPUT.PUT_LINE(GET_TABL_LIST.TABLE_NAME || ' - ' || table_row);
END LOOP;
END;
About the ordering, simply add an ORDER BY to the query looping through the tables
This assumes that you have rights to query all the tables listed in ALL_TABLES If you simply need to query all the tables of your schema, use USER_TABLES instead of ALL_TABLES.
to sort the results add order by clausel:
FOR GET_TABL_LIST IN
(
SELECT TABLE_NAME
FROM ALL_TABLES
ORDER BY TABLE_NAME --
)LOOP
to count the records use dynamic sql :
execute immediate 'select count(*) from ' || V_TABL_NM INTO table_row;
This can be done completely without PL/SQL:
select table_name,
to_number(extractvalue(xmltype(dbms_xmlgen.getxml('select count(*) c from '||table_name)),'/ROWSET/ROW/C')) as rowcount
from user_tables
order by rowcount;
also I did:
select TABLE_NAME, NUM_ROWS, LAST_ANALYZED
from user_tables
order by 1;

How to determine row count for all tables in an Oracle Schema [duplicate]

I am trying to get the record counts of all tables in a schema. I am having trouble writing the PL/SQL. Here is what I have done so far, but I am getting errors. Please suggest any changes:
DECLARE
v_owner varchar2(40);
v_table_name varchar2(40);
cursor get_tables is
select distinct table_name,user
from user_tables
where lower(user) = 'SCHEMA_NAME';
begin
open get_tables;
fetch get_tables into v_table_name,v_owner;
INSERT INTO STATS_TABLE(TABLE_NAME,SCHEMA_NAME,RECORD_COUNT,CREATED)
SELECT v_table_name,v_owner,COUNT(*),TO_DATE(SYSDATE,'DD-MON-YY') FROM v_table_name;
CLOSE get_tables;
END;
This can be done with a single statement and some XML magic:
select table_name,
to_number(extractvalue(xmltype(dbms_xmlgen.getxml('select count(*) c from '||owner||'.'||table_name)),'/ROWSET/ROW/C')) as count
from all_tables
where owner = 'FOOBAR'
This should do it:
declare
v_count integer;
begin
for r in (select table_name, owner from all_tables
where owner = 'SCHEMA_NAME')
loop
execute immediate 'select count(*) from ' || r.table_name
into v_count;
INSERT INTO STATS_TABLE(TABLE_NAME,SCHEMA_NAME,RECORD_COUNT,CREATED)
VALUES (r.table_name,r.owner,v_count,SYSDATE);
end loop;
end;
I removed various bugs from your code.
Note: For the benefit of other readers, Oracle does not provide a table called STATS_TABLE, you would need to create it.
select owner, table_name, num_rows, sample_size, last_analyzed from all_tables;
This is the fastest way to retrieve the row counts but there are a few important caveats:
NUM_ROWS is only 100% accurate if statistics were gathered in 11g and above with ESTIMATE_PERCENT => DBMS_STATS.AUTO_SAMPLE_SIZE (the default), or in earlier versions with ESTIMATE_PERCENT => 100. See this post for an explanation of how
the AUTO_SAMPLE_SIZE algorithm works in 11g.
Results were generated as of LAST_ANALYZED, the current results may be different.
If you want simple SQL for Oracle (e.g. have XE with no XmlGen) go for a simple 2-step:
select ('(SELECT ''' || table_name || ''' as Tablename,COUNT(*) FROM "' || table_name || '") UNION') from USER_TABLES;
Copy the entire result and replace the last UNION with a semi-colon (';'). Then as the 2nd step execute the resulting SQL.
Get counts of all tables in a schema and order by desc
select 'with tmp(table_name, row_number) as (' from dual
union all
select 'select '''||table_name||''',count(*) from '||table_name||' union ' from USER_TABLES
union all
select 'select '''',0 from dual) select table_name,row_number from tmp order by row_number desc ;' from dual;
Copy the entire result and execute
You have to use execute immediate (dynamic sql).
DECLARE
v_owner varchar2(40);
v_table_name varchar2(40);
cursor get_tables is
select distinct table_name,user
from user_tables
where lower(user) = 'schema_name';
begin
open get_tables;
loop
fetch get_tables into v_table_name,v_owner;
EXIT WHEN get_tables%NOTFOUND;
execute immediate 'INSERT INTO STATS_TABLE(TABLE_NAME,SCHEMA_NAME,RECORD_COUNT,CREATED)
SELECT ''' || v_table_name || ''' , ''' || v_owner ||''',COUNT(*),TO_DATE(SYSDATE,''DD-MON-YY'') FROM ' || v_table_name;
end loop;
CLOSE get_tables;
END;

How to select from a parameter (cursor,varchar2, etc)

I have a little problem and if you could help me it would be great.
DECLARE
CURSOR cur1 IS
SELECT table_name
FROM all_tab_columns
WHERE column_name LIKE 'DESCRIPTION';
tableName varchar2(100);
BEGIN
OPEN cur1;
LOOP
FETCH cur1 INTO tableName;
EXIT WHEN cur1%NOTFOUND;
dbms_output.put_line(tablename);
END LOOP;
END;
What I need is to get all the information possible from those tables with the condition:
WEHRE DESCRIPTION LIKE 'Transaction%'
Something like this
SELECT *
FROM tableName ---- from above
WEHRE DESCRIPTION LIKE 'Transaction%'
I would like to select all data from the tables in my cursor.
The tables don't have the same structure, one can have 4 coloumns, one can have 10 coloumns.
Can it be done in an anonymous block?
Can anyone help me, please?
Try this:
DECLARE
CURSOR cur1 IS
SELECT table_name
FROM user_tab_columns
WHERE column_name LIKE 'DESCRIPTION';
tableName varchar2(100);
l_description varchar2(100);
l_str_val varchar2(100) := 'Transaction%';
l_cursor sys_refursor;
BEGIN
OPEN cur1;
LOOP
FETCH cur1 INTO tableName;
EXIT WHEN cur1%NOTFOUND;
open l_cursor for 'select DESCRIPTION from ' || tableName || ' where DESCRIPTION like :description' using l_str_val;
loop
fetch l_cursor into l_description;
exit when l_cursor%NOTFOUND;
dbms_output.put_line(tablename || ' ' || l_description);
end loop;
close l_cursor;
END LOOP;
close cur1;
END;
I extracted only description column, because I am sure this column is in the table, if you want to extract more columns you have to rewrite this like:
WHERE column_name = ('DESCRIPTION', 'ID', NAME)
and then:
execute immediate 'select DESCRIPTION, ID, NAME from ' || tableName || ' where DESCRIPTION like :description' into l_description, l_id, l_name using l_str_val;

Row count of all tables in a schema

DECLARE
v_owner varchar2(40);
v_table_name varchar2(40);
cursor get_tables is
select distinct table_name
, user
from user_tables
where lower(user) = 'schema_name'
;
BEGIN
OPEN get_tables;
LOOP
FETCH get_tables
INTO v_table_name
, v_owner
;
EXIT WHEN get_tables%NOTFOUND;
EXECUTE IMMEDIATE
'INSERT
INTO STATS_TABLE
( TABLE_NAME
, SCHEMA_NAME
, RECORD_COUNT
, CREATED
)
SELECT '''
|| v_table_name
|| ''' , ''' || v_owner
|| ''' , COUNT(*)
, TO_DATE(SYSDATE,''DD-MON-YY'')
FROM ' || v_table_name
;
END LOOP;
CLOSE get_tables;
END;
I am using this to get row counts of all tables in a schema. I got this query from stackoverflow.
I ran this as a procedure its successfully compiled but i am unable to view the result y is it so?
I am new to pl/sql can anyone explain what does the select statement do after the excute immediate query I am unable to understand the logic behind.
Try this:
select TABLE_NAME, NUM_ROWS from dba_tables where owner = 'xxxxx'
You can simply get row count against tables by:
select owner, table_name, nvl(num_rows,-1)
from all_tables
order by nvl(num_rows,-1) desc
https://livesql.oracle.com/apex/livesql/file/content_EPJLBHYMPOPAGL9PQAV7XH14Q.html
The row counts are inserted into a table name STATS_TABLE. You need to run a
select *
from stats_table
after running the procedure
This procedure is running successfully
DECLARE
v_owner varchar2(40);
v_table_name varchar2(40);
cursor get_tables is
select distinct table_name, user
from user_tables
where lower(user) = 'coreown' ;
BEGIN
OPEN get_tables;
LOOP
FETCH get_tables
INTO v_table_name, v_owner;
EXIT WHEN get_tables%NOTFOUND;
EXECUTE IMMEDIATE 'INSERT
INTO STATS_TABLE
( TABLE_NAME
, SCHEMA_NAME
, RECORD_COUNT
, CREATED
)
SELECT ''' || v_table_name ||
''' , ''' || v_owner || ''' , COUNT(*)
, TO_DATE(SYSDATE,''DD-MON-YY'')
FROM ' || v_table_name;
END LOOP;
CLOSE get_tables;
END;
/
I tried at my end.
After executing USE COMMIT.So that it will save the change is DB.
Then check again.
Well, user_tables does not have a user column, so that query is invalid. Always test the queries in isolation -- you probably want all_tables or dba_tables. Also, do you think you need a DISTINCT on that query?
Use an implicit cursor instead of an explicit one wherever you can -- less code, less error prone in coding, and faster.
Do not store dates as character types -- you just insert sysdate, not a representation of it as a string.
Don't prefix variable names with "v_" -- just namespace them with the procedure or block name.
The Execute Immediate constructs a SQL statement that performs an insert into the stats_table (why does it have the word "table" in the name? That's redundant, surely?)
The query will be constructed as something like:
INSERT INTO STATS_TABLE
( TABLE_NAME
, SCHEMA_NAME
, RECORD_COUNT
, CREATED
)
SELECT 'MY_TABLE_NAME' , 'MY_USERNAME' , COUNT(*) , SYSDATE
FROM MY_TABLE_NAME;

Resources