How to listed all the tables of a User in a database? n - sql

Hi so i have the following plan :
i want to Write a script, which calls another script. A parameter V_USERNAME should be passed from the 1st script to the 2nd script.( Using the keyword DEFINE)
My code look like :
##C:\Users\pe.k\Documents\script2.sql &p_v_username
set serveroutput on
define p_v_username = "user";
In the 2nd script all tables of the user should be output. (Using the key word EXECUTE IMMEDIATE and a cursor).
The output control is to be done via a parameter in the script or when calling the script.
Example call:
SQL> #start_script1 MML
declare
&p_v_username varchar2(100);
v_result varchar2(100);
cursor cp_username (&p_v_username varchar2)
is
select owner, table_name
from all_tables
where owner = &p_v_username
order by owner, table_name;
begin
dbms_output.put_line('Alle Tabellen der User'); --l_username);
open cp_username(&p_v_username);
--loop
--fetch cp_username into v_result;
-- dbms_output.put_line(v_result);
--end loop;
close cp_username;
end;
/
And i have the errors and i am lost. I dont know how to do it

Your second procedure should be something like this:
BEGIN
DBMS_OUTPUT.PUT_LINE('Alle Tabellen der User'); --l_username);
FOR TABS IN (
SELECT OWNER, TABLE_NAME
FROM ALL_TABLES
WHERE OWNER = '&P_V_USERNAME'
ORDER BY OWNER, TABLE_NAME
) LOOP
DBMS_OUTPUT.PUT_LINE(TABS.TABLE_NAME);
END LOOP;
END;
/
In order to print the output generated by the DBMS_OUTPUT package from PL/SQL, make sure to set serveroutput on

Related

How can I set a cursor on a select statement with dynamic table_name in PL/SQL?

I created a PL/SQL procedure that takes the name of user and shows a list of his tables' content. The problem is that I couldn't set the cursor to accept a different table name each time and show its content.
Here is my code which is not complete yet.
set serveroutput on;
create or replace procedure userTable(name dba_tables.owner%type)
is
cursor cur is select table_name from dba_tables where owner = upper(name);
cursor cur2(tab_name dba_tables.table_name%type) is select * from name.tab_name;
V$FILEP UTL_FILE.FILE_TYPE;
begin
if existUser(name) = true then
V$FILEP := UTL_FILE.FOPEN('DIRTEST','TEST15.UTL','W');
for x in cur loop
UTL_FILE.PUT_LINE(V$FILEP,to_char(x.table_name));
end loop;
UTL_FILE.FCLOSE(V$FILEP);
else
dbms_output.put_line('user invalid');
end if;
end;
/

PL/SQL - Return cursor that selects data from loop

I have the following problem with PL/SQL:
I'm trying to write a PL/SQL Statement for an Oracle Cloud Control Metric Extension.
The Metric wants a CURSOR as result:
The PL/SQL has to end with something like the following
OPEN :1 FOR SELECT var1, var2 FROM DUAL;
The bind variable 1 and the Type "SQL_CURSOR" is defined by the application.
My Code looks like this:
DECLARE
v_ts_id NUMBER;
tbspname VARCHAR2(200);
CURSOR all_tablespaces IS
select distinct tablespace_name
from dba_tablespaces
where tablespace_name not in ('UNDO','TEMP');
BEGIN
FOR v_ts_name IN all_tablespaces LOOP
tbspname := UPPER(v_ts_name.tablespace_name);
SELECT ts# into v_ts_id
FROM v$tablespace
where name = tbspname;
END LOOP;
OPEN :1 FOR SELECT v_ts_id, tbspname FROM DUAL;
END;
As result I get one row. Makes sense, because the cursor just selects the last values stored in v_ts_id and tbspname.
But how can I get the cursor to select all rows?
I don't want to create a table to store the values.
The following works on SQL*Plus
set serverout on
set verify off
set lines 200
set pages 2000
DECLARE
v_ts_id number;
tbspname varchar2(200);
CURSOR all_tablespaces IS
select distinct tablespace_name
from dba_tablespaces
where tablespace_name not in ('UNDO','TEMP');
BEGIN
FOR v_ts_name IN all_tablespaces LOOP
tbspname := UPPER(v_ts_name.tablespace_name);
SELECT ts# into v_ts_id
FROM v$tablespace
where name = tbspname;
DBMS_OUTPUT.PUT_LINE(v_ts_id ||','||tbspname);
END LOOP;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Tablespace usage information not found in AWR');
END;
/
Part of the RESULT looks like this:
5,USERS
1,SYSAUX
0,SYSTEM
I want the same result like in the second example returned by the Cursor in my code?
I think the loop is irreplaceable because some more data will be processed later for every tablespace.
The simple approach would be to simply do a join
begin
open :1
for select vt.ts#, dt.tablespace_name
from v$tablespace vt
join dba_tablespaces dt
on vt.tablespace_name = dt.tablespace_name
where dt.tablespace_name not in ('UNDO','TEMP');
end;
If you really must do a loop, something like this should work
create type my_ts_obj as object (
ts# integer,
tablespace_name varchar2(30)
);
create type my_ts_nt is table of my_ts_obj;
declare
l_ts my_ts_nt := new my_ts_nt();
l_ts# integer;
begin
for dt in (select distinct tablespace_name
from dba_tablespaces
where tablespace_name not in ('UNDO','TEMP'))
loop
select vt.ts#
into l_ts#
from v$tablespace vt
where vt.tablespace_name = dt.tablespace_name;
l_ts.extend();
l_ts( l_ts.count ) := new my_ts_obj( l_ts#, dt.tablespace_name );
end loop;
open :1
for select *
from table( l_ts );
end;

oracle - concatenate in select for drop, create, grant - lost in ''''

I am new to Oracle database, got a task to write several selects, but I do not get somethow principle, how it works (or better to say does not work). Could you please help me to find a mistake and probably you have a link to some info or converter that helps such writings.
v_sql := 'SELECT ''DROP TABLE ''||object_name||'' as
select *
FROM all_objects
WHERE object_name LIKE '''%''|| v_date ||''%'''
and object_type = ''TABLE''
and owner =''||v_owner||''';
Are you trying to generate DROP statements for a specific user? Start with the below anonymous block and add to it.
--Generate DROP statements for all tables for a user.
declare
v_owner varchar2(128) := user;
begin
for objects in
(
select distinct 'DROP TABLE "'||owner||'"."'||object_name||'"' v_sql
from all_objects
where object_type = 'TABLE'
and owner = v_owner
order by v_sql
) loop
dbms_output.put_line(objects.v_sql);
end loop;
end;
/

Create a simple store procedure in oracle 12c

I am looking to create a simple store procedureto return a list of all user names in a table called dba_users.
The select I am using is:
SELECT username FROM dba_users
When I create a PROCEDURE with the following syntax it is created, but fails to execute:
CREATE OR REPLACE PROCEDURE user_list_display
IS
BEGIN
SELECT username FROM dba_users
END;
For this I get
ORA-00900: invalid SQL statement:
EXECUTE user_list_display;
you had better using an implicit cursor with dbms_output.put_line:
SQL> set serveroutput on;
SQL> CREATE OR REPLACE PROCEDURE user_list_display IS
BEGIN
FOR c in ( SELECT username FROM dba_users )
LOOP
dbms_output.put_line(c.username);
END LOOP;
END;
/
SQL> exec user_list_display;
In Oracle12c, You can use DBMS_SQL.RETURN_RESULT.
CREATE OR REPLACE PROCEDURE user_list_display
IS
v_cursor SYS_REFCURSOR;
BEGIN
OPEN v_cursor FOR SELECT username FROM dba_users;
DBMS_SQL.RETURN_RESULT ( v_cursor );
END;
/
Then execute it as
EXEC user_list_display;
In lower versions,from SQL* Plus (or execute as script in SQL Developer ), you may use a REFCURSOR OUT variable and PRINT to display the result.
CREATE OR REPLACE PROCEDURE user_list_display( output OUT SYS_REFCURSOR )
IS
BEGIN
OPEN output FOR SELECT username FROM dba_users;
END;
/
You may run these 3 lines whenever you want to see the output.
VARIABLE output REFCURSOR
EXEC user_list_display(:output)
PRINT output

Execute Immediate within a stored procedure keeps giving insufficient priviliges error

Here is the definition of the stored procedure:
CREATE OR REPLACE PROCEDURE usp_dropTable(schema VARCHAR, tblToDrop VARCHAR) IS
BEGIN
DECLARE v_cnt NUMBER;
BEGIN
SELECT COUNT(*)
INTO v_cnt
FROM all_tables
WHERE owner = schema
AND table_name = tblToDrop;
IF v_cnt > 0 THEN
EXECUTE IMMEDIATE('DROP TABLE someschema.some_table PURGE');
END IF;
END;
END;
Here is the call:
CALL usp_dropTable('SOMESCHEMA', 'SOME_TABLE');
For some reason, I keep getting insufficient privileges error for the EXECUTE IMMEDIATE command. I looked online and found out that the insufficient privileges error usually means the oracle user account does not have privileges for the command used in the query that is passes, which in this case is DROP. However, I have drop privileges. I am really confused and I can't seem to find a solution that works for me.
Thanks to you in advance.
SOLUTION:
As Steve mentioned below, Oracle security model is weird in that it needs to know explicitly somewhere in the procedure what kind of privileges to use. The way to let Oracle know that is to use AUTHID keyword in the CREATE OR REPLACE statement. If you want the same level of privileges as the creator of the procedure, you use AUTHID DEFINER. If you want Oracle to use the privileges of the user currently running the stored procedure, you want to use AUTHID CURRENT_USER. The procedure declaration looks as follows:
CREATE OR REPLACE PROCEDURE usp_dropTable(schema VARCHAR, tblToDrop VARCHAR)
AUTHID CURRENT_USER IS
BEGIN
DECLARE v_cnt NUMBER;
BEGIN
SELECT COUNT(*)
INTO v_cnt
FROM all_tables
WHERE owner = schema
AND table_name = tblToDrop;
IF v_cnt > 0 THEN
EXECUTE IMMEDIATE('DROP TABLE someschema.some_table PURGE');
END IF;
END;
END;
Thank you everyone for responding. This was definitely very annoying problem to get to the solution.
Oracle's security model is such that when executing dynamic SQL using Execute Immediate (inside the context of a PL/SQL block or procedure), the user does not have privileges to objects or commands that are granted via role membership. Your user likely has "DBA" role or something similar. You must explicitly grant "drop table" permissions to this user. The same would apply if you were trying to select from tables in another schema (such as sys or system) - you would need to grant explicit SELECT privileges on that table to this user.
You should use this example with AUTHID CURRENT_USER :
CREATE OR REPLACE PROCEDURE Create_sequence_for_tab (VAR_TAB_NAME IN VARCHAR2)
AUTHID CURRENT_USER
IS
SEQ_NAME VARCHAR2 (100);
FINAL_QUERY VARCHAR2 (100);
COUNT_NUMBER NUMBER := 0;
cur_id NUMBER;
BEGIN
SEQ_NAME := 'SEQ_' || VAR_TAB_NAME;
SELECT COUNT (*)
INTO COUNT_NUMBER
FROM USER_SEQUENCES
WHERE SEQUENCE_NAME = SEQ_NAME;
DBMS_OUTPUT.PUT_LINE (SEQ_NAME || '>' || COUNT_NUMBER);
IF COUNT_NUMBER = 0
THEN
--DBMS_OUTPUT.PUT_LINE('DROP SEQUENCE ' || SEQ_NAME);
-- EXECUTE IMMEDIATE 'DROP SEQUENCE ' || SEQ_NAME;
-- ELSE
SELECT 'CREATE SEQUENCE COMPTABILITE.' || SEQ_NAME || ' START WITH ' || ROUND (DBMS_RANDOM.VALUE (100000000000, 999999999999), 0) || ' INCREMENT BY 1'
INTO FINAL_QUERY
FROM DUAL;
DBMS_OUTPUT.PUT_LINE (FINAL_QUERY);
cur_id := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.parse (cur_id, FINAL_QUERY, DBMS_SQL.v7);
DBMS_SQL.CLOSE_CURSOR (cur_id);
-- EXECUTE IMMEDIATE FINAL_QUERY;
END IF;
COMMIT;
END;
/
you could use "AUTHID CURRENT_USER" in body of your procedure definition for your requirements.
Alternatively you can grant the user DROP_ANY_TABLE privilege if need be and the procedure will run as is without the need for any alteration. Dangerous maybe but depends what you're doing :)