Dynamic Sql, problem with binding - plsql

I have a block:
DECLARE
stmnt VARCHAR2(100);
rol VARCHAR2(10); --role name
tab_name VARCHAR2(10); --table name
BEGIN
rol := '&Role_name';
stmnt := 'create role ' || rol;
EXECUTE IMMEDIATE stmnt;
stmnt := 'grant :p on ' || '&tab_name' || ' to ' || rol;
EXECUTE IMMEDIATE stmnt using '&Privilege';
END;
when I execute this block, after enetering the privilege SELECT, Oracle gives me an error that missing or invalid privilege ORA-00990: missing or invalid privilege
Why it doesn't bind variable?

You cannot bind Oracle names, only data values. Do this instead:
DECLARE
stmnt VARCHAR2(100);
rol VARCHAR2(10); --role name
tab_name VARCHAR2(10); --table name
BEGIN
rol := '&Role_name';
stmnt := 'create role ' || rol;
EXECUTE IMMEDIATE stmnt;
stmnt := 'grant &Privilege. on &tab_name. to ' || rol;
EXECUTE IMMEDIATE stmnt;
END;

Related

How to get single output from PL/SQL procedure having select statement

I am trying to execute one PL/SQL procedure. I am getting nullpointerexception every time. Might be I am returning the procedure in wrong way.
Can you please help me in this procedure.
PROCEDURE p_regidexport(countryid IN varchar2, cropid IN varchar2, productid IN VARCHAR2, pregid out varchar)
IS
fnc VARCHAR2(30) := 'P_REGIDEXPORT';
query VARCHAR2(10000);
regid varchar(20);
BEGIN
select REG_ID into regid from GRS_Registration where LOC_ID =(select loc_id from GRS_location where Country = ' || countryid || ') AND CROP_ID = (select crop_id from GRS_crop where CROP_NM = ' || cropid || ')AND REG_NAME =' || '''' || productid || ''';
pregid := regid;
sub_log('P_REGIDEXPORT:'||pregid);
dbms_output.put_line(pregid);
EXCEPTION
WHEN no_data_found THEN
dbms_output.put_line('No record present');
END P_REGIDEXPORT;
you need not to concatenate in parameter value. because its not dynamic query. so, you can directly pass the parameter variable into ur query.
make sure that your qry will return one single value.
its just idea based upon ur code, u can try based upon ur requirement.
Hope it will help you!!
create or replace PROCEDURE p_regidexport(countryid IN varchar2, cropid IN varchar2, productid IN VARCHAR2, pregid out varchar)
IS
fnc VARCHAR2(30) := 'P_REGIDEXPORT';
query VARCHAR2(10000);
regid varchar(20);
BEGIN
begin
select nvl(REG_ID,'0') into regid from GRS_Registration
where
LOC_ID =(select loc_id from GRS_location where Country = countryid ) AND
CROP_ID = (select crop_id from GRS_crop where CROP_NM = cropid)AND
REG_NAME = productid ;
EXCEPTION
WHEN no_data_found THEN
dbms_output.put_line('No record '); --- or regid ='0';
end;
pregid := regid;
--sub_log('P_REGIDEXPORT:'||pregid);
dbms_output.put_line(pregid);
EXCEPTION
WHEN others THEN
dbms_output.put_line('No record present' || ' - ' || sqlerrm);
END P_REGIDEXPORT;
All the best!! if it is useful click up button which is in left side of this answer

How do packages work?

I've created a package with two procedures, one of which is to create a user. However when I execute the procedure although successful, I'm not seeing the user created..
create or replace PACKAGE APPLICATIONPACKAGE AS
procedure CreateSingleUser( userName in VARCHAR2, rolename in VARCHAR2);
PROCEDURE DeleteUser(userName in varchar2);
END APPLICATIONPACKAGE;
/
create or replace PACKAGE BODY
APPLICATIONPACKAGE AS
procedure CreateSingleUser( userName in VARCHAR2, rolename in VARCHAR2)
AS
dynamicsql VARCHAR2 (2000);
BEGIN
BEGIN
if rolename='APPADMIN' OR rolename='APPMODIFIER' or rolename='APPVIEWER'
THEN --limit user input to specific roles
----assign dynamic sql to a variable for excecution by excecute immediate
dynamicsql :='CREATE USER ' || userName|| ' IDENTIFIED BY pass1234 DEFAULT
TABLESPACE USERS QUOTA 1M ON USERS PASSWORD EXPIRE';
DBMS_OUTPUT.PUT_LINE (dynamicsql);
EXECUTE IMMEDIATE dynamicsql;
EXECUTE IMMEDIATE 'GRANT ' || rolename || ' TO ' || userName || '';
EXECUTE IMMEDIATE 'GRANT CREATE SESSION TO ' || userName;
else
DBMS_OUTPUT.PUT_LINE('Not a valid role...sorry role specified not given to
a user');
END IF;
END;
END CreateSingleUser;
PROCEDURE DeleteUser(userName in varchar2)
AS
deleteSql VARCHAR2 (500);
BEGIN
deleteSql :='DROP USER ' || userName; -- assign drop user command to
variable delete sql
DBMS_OUTPUT.PUT_LINE (deleteSql);
EXECUTE IMMEDIATE deleteSql; -- excecute the sql dynamically;
END DeleteUser;
----- end procedure delete user-------
END APPLICATIONPACKAGE;

Error in plsql code

Pleas help me to resolve this error in plsql.
sqlquery := 'SELECT COUNT(*) FROM V$SESSION WHERE STATUS = 'INACTIVE' AND LAST_CALL_ET > 0';
EXECUTE IMMEDIATE sqlquery into s_count;
below is the error:
ERROR at line 57:
ORA-06550: line 57, column 66:
PLS-00103: Encountered the symbol "INACTIVE" when expecting one of the following:
* & = - + ; < / > at in is mod remainder not rem
<an exponent (**)> <> or != or ~= >= <= <> and or like like2
like4 likec between || multiset member submultiset
The symbol "* was inserted before "INACTIVE" to continue.
ORA-06550: line 79, column 4:
PLS-00103: Encountered the symbol "EXCEPTION" when expecting one of the following:
( begin case declare else elsif end exit for goto if loop mod
null pragma raise return select update while with <an identifier> <a double-quoted
ORA-06550: line 81, column 7:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
end not pragma final instantiable order overriding static member constructor map
The quotes around INACTIVE are splitting the string up and causing the syntax error...
sqlquery := 'SELECT COUNT(*) FROM V$SESSION WHERE STATUS = ''INACTIVE'' AND LAST_CALL_ET > 0';
EXECUTE IMMEDIATE sqlquery into s_count;
Of course, if the statement isn't actually dynamic you don't need the EXECUTE IMMEDIATE and can instead go with:
SELECT COUNT(*)
INTO s_count
FROM V$SESSION
WHERE STATUS = 'INACTIVE'
AND LAST_CALL_ET > 0';
set serveroutput on;
declare
l_status varchar2(30):= 'INACTIVE';
s_count number:= 0;
sqlquery varchar2(32767) := null;
begin
sqlquery := 'SELECT COUNT(*) FROM V$SESSION WHERE STATUS = :a AND LAST_CALL_ET > 0';
EXECUTE IMMEDIATE sqlquery into s_count using l_status ;
dbms_output.put_line(s_count);
end;
Use the following query:
sqlquery := 'SELECT COUNT(*) FROM V$SESSION WHERE STATUS = ''INACTIVE'' AND LAST_CALL_ET > 0';
Solution with Execute immediate
set serveroutput on;
declare
l_status varchar2(30):= '''INACTIVE''';
s_count number:= 0;
sqlquery varchar2(32767) := null;
begin
sqlquery := 'SELECT COUNT(*) FROM V$SESSION WHERE STATUS = '||l_status||' AND LAST_CALL_ET > 0';
EXECUTE IMMEDIATE sqlquery into s_count;
dbms_output.put_line(s_count);
end;
EXECUTE IMMEDIATE '
SELECT COUNT(*)
FROM V$SESSION
WHERE STATUS = ''INACTIVE'' AND LAST_CALL_ET > 0'
INTO s_count;
Please change the query as
sqlquery := 'SELECT COUNT(*) FROM V$SESSION WHERE STATUS = '''INACTIVE''' AND LAST_CALL_ET > 0';
EXECUTE IMMEDIATE sqlquery into s_count;
Bind variables like Chandra said!
One way I like to assign the SQL:
declare
vSQL varchar2( 100 ) ;
begin
vSQL := q'[select 'done' from dual ]' ;
dbms_output.put_line( vSQL ) ;
end ;
so you'd do:
sqlquery := q'[SELECT COUNT(*) FROM V$SESSION WHERE STATUS = :status AND LAST_CALL_ET > 0]';
use :
sqlquery := 'SELECT COUNT(*) FROM V$SESSION WHERE STATUS = ''INACTIVE'' AND LAST_CALL_ET > 0';
not :
sqlquery := 'SELECT COUNT(*) FROM V$SESSION WHERE STATUS = 'INACTIVE' AND LAST_CALL_ET > 0';
use this code will work perfectly
set serveroutput on
DECLARE
sqlquery varchar2(1000);
INACTIVE varchar2(100):='INACTIVE';
s_count number;
begin
sqlquery := 'SELECT COUNT(*) FROM V$SESSION WHERE STATUS = '''||INACTIVE||''' AND LAST_CALL_ET > 0';
EXECUTE IMMEDIATE sqlquery into s_count;
DBMS_OUTPUT.PUT_LINE(s_count);
end;
/
Another way to do this:
set serveroutput on;
DECLARE
sqlquery VARCHAR2(4000);
s_count number;
begin
sqlquery := 'SELECT COUNT(*) FROM V$SESSION WHERE STATUS = '||chr(39)||'INACTIVE'||chr(39)||' AND LAST_CALL_ET > 0';
EXECUTE IMMEDIATE sqlquery into s_count;
dbms_output.put_line('s_count--'||s_count);
end;
/

PL/SQL DDL Execute Immediate

ACCEPT p_username PROMPT 'Enter Username : '
ACCEPT p_password PROMPT 'Enter New Password for Username : '
VARIABLE g_output VARCHAR2(4000)
DECLARE
CURSOR NAME IS SELECT TABLE_NAME FROM DBA_TABLES
WHERE OWNER LIKE '%&p_username%';
DDL_DROP VARCHAR2(200);
BEGIN
FOR TNAME IN NAME
LOOP
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE' || ' ' || TNAME.TABLE_NAME;
:g_output := :g_output || ' ' || TNAME.TABLE_NAME;
END;
END LOOP;
END;
/
PRINT g_output
Hello, I'm new to PL/SQL and trying to make a script to drop the user's table and ultimately change their password later after dropping their tables. I am having difficulty with the EXECUTE IMMEDIATE command. The script works if I remove the EXECUTE IMMEDIATE line. I tested it by printing the table names inside the loop and I get the right # of tables and their corresponding names.
Any help is appreciated, thanks.
Edited the code to reflect the suggestion but still didn't work. Getting the same error.
ACCEPT p_username PROMPT 'Enter Username : '
ACCEPT p_password PROMPT 'Enter New Password for Username : '
VARIABLE g_output VARCHAR2(4000)
DECLARE
NAME SYS_REFCURSOR;
DDL_WORD VARCHAR2(200);
BEGIN
OPEN NAME FOR SELECT TABLE_NAME FROM DBA_TABLES
WHERE OWNER LIKE '%&p_username%';
LOOP
FETCH NAME INTO DDL_WORD;
EXIT WHEN NAME%NOTFOUND;
EXECUTE IMMEDIATE 'DROP TABLE "' || DDL_WORD || '" CASCADE CONSTRAINTS';
:g_output := :g_output || ' ' || DDL_WORD;
END LOOP;
CLOSE NAME;
END;
/
PRINT g_output
You probably need to specify the owner for the table in the DROP statement:
ACCEPT p_username PROMPT 'Enter Username : '
ACCEPT p_password PROMPT 'Enter New Password for Username : '
VARIABLE g_output VARCHAR2(4000)
DECLARE
CURSOR NAME IS SELECT OWNER, TABLE_NAME FROM DBA_TABLES
WHERE OWNER LIKE '%&p_username%';
DDL_DROP VARCHAR2(200);
BEGIN
FOR TNAME IN NAME
LOOP
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE' || ' ' || TNAME.OWNER || '.' || TNAME.TABLE_NAME;
:g_output := :g_output || ' ' || TNAME.OWNER || '.' || TNAME.TABLE_NAME;
END;
END LOOP;
END;
/
PRINT g_output
The code looks fine.
You could try with () like this
BEGIN
EXECUTE IMMEDIATE (code_text);
END;
You could try
c SYS_REFCURSOR;
BEGIN
OPEN c FOR 'SELECT * FROM table';
CLOSE c;
END;

PLSQL error - ORA-00984: column not allowed here

I have written a PL-SQL block
DECLARE
SchemaName VARCHAR2(50) :='REQ_SUNIL_5750';
userpassword VARCHAR2(50) :='XYZ';
stmt VARCHAR2(5000);
BEGIN
stmt :='INSERT INTO ' || SchemaName || '.USER_CREDS VALUES ('|| SchemaName ||', '|| userpassword ||' )';
DBMS_OUTPUT.PUT_LINE(stmt) ;
EXECUTE IMMEDIATE stmt;
commit;
END;
When I execute above block I am getting below,
ORA-00984: column not allowed here
I have created table with name 'REQ_SUNIL_5750.USER_CREDS and it has username and password columns
Please help
You have to quote your string values properly:
stmt :='INSERT INTO ' || SchemaName ||
'.USER_CREDS VALUES ('''|| SchemaName ||''', '''|| userpassword ||''' )';
Frank's answer is great, I would add one point though.
From the perspective of performance and reuseability, your execute immediate statement should use bind variables and the insert syntax should specify the columns that correspond to the values being entered.

Resources