Table names, and loop to describe - sql

Working in Oracle 10g. Easy way to list all tables names (select table_name from dba_tables where owner = 'me')
But now that I have the table names, is there an easy way to loop through them and do a 'describe' on each one in sequence?

You could query against DBA_TAB_COLUMNS (or USER_TAB_COLUMNS).
Nicolas.

Not sure you can do a describe from within PL/SQL. I just tried using execute immediate 'describe some_table', that doesn't work either. Your next choice would be to query DBA_TAB_COLUMNS, or create a new file with all your describe statements (using dbms_output from pl/sql and spool to create the file) and then execute that file. Maybe like this:
spool temp_file.sql
BEGIN
/*or you could have a loop here with as many put_lines as you need, it will all end up in the new script file.*/
dbms_output.put_line('describe some_table');
END;
/
spool off
#temp_file.sql
/*I have not actually tried running this code, beware syntax errors!*/

You can do this in PL/SQL using DBMS_METADATA.GET_DDL, e.g. (example taken from docs):
SET LONG 2000000
SET PAGESIZE 0
SELECT DBMS_METADATA.GET_DDL('TABLE','EMP','SCOTT') FROM DUAL;

login with the user and then run the following commands, first file will contain the describe commands and the second file will be the desired file containing all the descriptions of all tables for logged in user
spool desctables.sql
select 'describe '||table_name||';' from user_tables;
spool off
spool alltables.txt
#desctables.sql
spool off

I'd recommend querying dba_tab_columns, as N. Gasparotto suggested, but if you really want describe output then create a file mulit-describe.sql with the following:
set pagesize 0
set termout off
set feedback off
set verify off
spool mdtmp.sql
select 'describe ' || owner || '.' || table_name
from dba_tables
where OWNER = upper('&1')
/
spool off
set termout on
#mdtmp.sql
Within SQL*PLUS run by:
#multi-describe ME

Related

How to execute alter command within select statement in a loop in Oracle?

I am trying to Rebuild Indexes of a schema through a script but I am stucked at a point where I get the string ALTER INDEX OWNER.INDEX_NAME REBUILD NOLOGGING through select statement but I am not getting how to execute the alter command ,please guide :
I tried to assign str the value of select query used in 2nd for loop and then execute it but it gave error .
IS
STR VARCHAR2(5000);
BEGIN
FOR T IN (
SELECT USERNAME FROM DBA_USERS WHERE USERNAME ='REPORT'
)
LOOP
FOR CUR IN
(
SELECT ' ALTER INDEX '||OWNER||'.'||INDEX_NAME|| ' REBUILD NOLOGGING; ' FROM DBA_INDEXES
WHERE OWNER=T.USERNAME AND TEMPORARY='N'
)
LOOP
--- EXECUTE IMMEDIATE STR ;
INSERT INTO INDEX_REBUILD_HISTORY
SELECT DISTINCT OWNER, TRUNC(LAST_DDL_TIME) from DBA_OBJECTS where OBJECT_TYPE = 'INDEX'
AND
OWNER=T.USERNAME ;
COMMIT;
END LOOP;
END LOOP;
END ;
You use dynamic sql. And you don't need your outer loop. The filter on that is available in dba_indexes:
create procedure bld_idx
is
vsql varchar2(500);
for x in (select owner,
index_name
from dba_indexes
where owner = 'REPORT'
and TEMPORARY='N'
)
loop
vsql := ' ALTER INDEX '||x.OWNER||'.'||x.INDEX_NAME|| ' REBUILD NOLOGGING; ';
dbms_output.put_line(vsql); -- debugging only
execute immediate vsql;
end loop;
end;
Note 1: above is off the top of my head. There may be minor syntax issues, but if so you should be able to work them out.
Not 2: Rebuilding indexes is not something that needs to be done in the normal course of things. Richard Foote is probably the foremost authority on the internals of oracle indexes, and he has this to say: https://richardfoote.wordpress.com/2007/12/11/index-internals-rebuilding-the-truth/
"it gave error ." isn't helpful without the actual error you received. That said you've made the same mistake so many others do, you shouldn't include the ";" as part of your dynamic SQL - it's not part of the statement, it's only used by your client to know when to send code to the database.
FOR CUR IN
(
SELECT ' ALTER INDEX '||OWNER||'.'||INDEX_NAME|| ' REBUILD NOLOGGING' ddl_cmd FROM DBA_INDEXES
WHERE OWNER=T.USERNAME AND TEMPORARY='N'
)
...
EXECUTE IMMEDIATE CUR.ddl_cmd ;
(I've also given the column an alias so you can use it in your loop nicely.
Then
INSERT INTO INDEX_REBUILD_HISTORY
SELECT DISTINCT OWNER, TRUNC(LAST_DDL_TIME) from DBA_OBJECTS where OBJECT_TYPE = 'INDEX'
AND
OWNER=T.USERNAME ;
Is not filtering on the index you just rebuilt, it doesn't seem like it's going to get entirely useful information.
That said...
Is it really worth rebuilding all your indexes offline and making them unrecoverable? Probably not, if you're doing this more than once and are benefiting then there's probably something that could be changed with your data model to help. Have a good read of this presentation by Richard Foote, a well established Oracle Indexing Expert https://richardfoote.files.wordpress.com/2007/12/index-internals-rebuilding-the-truth.pdf I doubt you'd come away from it believing that rebuilding all the indexes is a solution.

Use Query result in ALTER statement (Oracle)

I am trying to create a script to update passwords for a large number of users listed in a given table.
alter user FOO identified by FOOWORD;
I can call the usernames via the following statement:
select owner from usertable_verson where rownum = 1
Is there a way to combine these two statements, so that the alter user command works for each result of the select command?
The eventual goal is to create a loop for each username in the selected column, and apply the password change to each.
you can do this via dynamic SQL
smth like this:
begin
for rc in (select owner from usertable_verson) loop
execute immediate 'alter user '||rc.owner||' identified by FOOWORD';
end loop;
end;

Oracle Spool using Dynamic SQL

I'm trying to pass a dynamic SQL statement to spool out to a text file using SQL*Plus, but I can't seem to execute the select statement I'm generating.
set linesize 10000 pagesize 0 embedded on
set heading off feedback off verify off trimspool on trimout on termout off
set underline off
COLUMN gen_sql NEW_VALUE gen_sql_
SELECT 'SELECT * FROM USER_TAB_COLS WHERE ROWNUM < 10' gen_sql_ FROM DUAL;
SPOOL 'myfilename.csv'
EXECUTE IMMEDIATE &gen_sql_
SPOOL OFF
/
I can't seem to use EXECUTE IMMEDIATE. Is there another way to execute the results of the select statement??
MORE DETAIL:
I have a set of views whose output I'd like to generate as formatted CSV files. I'm using dynamic SQL to create the formatting essentially. I generate something similar to:
SELECT TRIM(col1)||','||TRIM(col2)...FROM {myview}
I'm using the following to generate it this way:
COLUMN gen_sql NEW_VALUE gen_sql_
SELECT 'SELECT ' || LISTAGG ('TRIM('||COLUMN_NAME||')', '||'',''|| ')
WITHIN GROUP (ORDER BY COLUMN_ID) gen_sql FROM...
Anyway, I'm able generate this SQL statement and store into a SQL*PLUS variable, but I just need to execute it after the SPOOL statement so that it will print to the file. I'm not sure how to execute it. Normal statements work, such as:
SPOOL 'myfilename.csv'
SELECT 1 col1 FROM DUAL;
SPOOL OFF
/
So, it would seem reasonable that I could something similar but executing the contents of my variable like:
SPOOL 'myfilename.csv'
--- RUN MY DYNAMIC SQL ----
SPOOL OFF
/
I think this is what you're trying to achieve:
set linesize 10000 pagesize 0 embedded on
set heading off feedback off verify off trimspool on trimout on termout off
set underline off
SPOOL myfilename.sql
SELECT 'SELECT table_name||'',''||column_name FROM USER_TAB_COLS WHERE ROWNUM < 10;' gen_sql_ FROM DUAL;
SPOOL OFF
spool results.csv
#myfilename.sql
SPOOL OFF
I.e. first you spool the results of your query into a file, and then once the spool is complete, you call the script you just created, spooling the results of that into a separate file.
I believe you'll find EXECUTE IMMEDIATE is a PL/SQL command, so cannot be used directly in SQL or SQL*plus.
http://docs.oracle.com/cd/B12037_01/appdev.101/b10807/13_elems017.htm
Also, SPOOL is a SQL*Plus command, and cannot be used in PL/SQL ..
So you have a problem there ;)
Can you step back a bit and explain what it is you're trying to do ?
What is the requirements you have?
First you need to construct a sql dynamically using spool.
And then execute it.
set echo off
set verify off
set feedback off
set linesize 256
set pagesize 0
set term off
SPOOL 'myscript.sql'
SELECT * FROM USER_TAB_COLS WHERE ROWNUM < 10;
SPOOL OFF
set colsep ,
SPOOL myfile.csv
#myscript.sql
SPOOL OFF

Getting the create table command used in oracle 11g

How can I get the create table command which is used to create a table in oracle 11g so that I can copy the command and run it in another database? Please help.
select dbms_metadata.get_ddl('TABLE', 'YOUR_TABLE_NAME_GOES_HERE')
from dual;
Try to spool the output of the below query,
SELECT DBMS_METADATA.GET_DDL('TABLE',u.table_name)
FROM USER_TABLES u;
Like,
set pagesize 0
set long 90000
set feedback off
set echo off
spool schema.sql
SELECT DBMS_METADATA.GET_DDL('TABLE',u.table_name)
FROM USER_TABLES u WHERE TABLE_NAME = '<your_table>';
spool off;
Reference: http://www.dba-oracle.com/oracle_tips_dbms_metadata.htm
Please use the below Query
select dbms_metadata.get_ddl('TABLE','YOUR_TABLE_NAME','YOUR_SCHEMA_NAME') from dual;
if you use SQL Developer, select the table name , and right click to choose Open Declaration and then Click SQL tab on the window that opens!

SQL query inside a SQL Script

I have a SQL script, which spools data to a file.
Sample Existing SQL script:
whenever sqlerror exit failure rollback
spool test.txt
set serveroutput on
select * from emp;
spool off
/
But, I would like to write a SQL query in this script before spooling data.
I don't want to hardcode the name of the spooling file, so how could I get the file name from a table or lookup?
I want the code to be something like
var filename varchar2(30);
select fname into :filename from table where script = 'abcscript';
spool :filename
set serveroutput on
select * from emp;
spool off
/
Thanks.
COLUMN spool_file_name NEW_VALUE.spool_file_name NOPRINT
select fname spool_file_name
from table where script = 'abcscript';
SPOOL &spool_file_name
SET ECHO ON
select * from emp ;
SPOOL OFF
COLUMN spool_file_name CLEAR