Add multiple functions to oracle database from script [duplicate] - oracle11g

Just wondering if anyone can help with this, I have two PLSQL statements for altering tables (adding extra fields) and they are as follows:
-- Make GC_NAB field for Next Action By Dropdown
begin
if 'VARCHAR2' = 'NUMBER' and length('VARCHAR2')>0 and length('')>0 then
execute immediate 'alter table "SERVICEMAIL6"."ETD_GUESTCARE" add(GC_NAB VARCHAR2(10, ))';
elsif ('VARCHAR2' = 'NUMBER' and length('VARCHAR2')>0 and length('')=0) or
'VARCHAR2' = 'VARCHAR2' then
execute immediate 'alter table "SERVICEMAIL6"."ETD_GUESTCARE" add(GC_NAB VARCHAR2(10))';
else
execute immediate 'alter table "SERVICEMAIL6"."ETD_GUESTCARE" add(GC_NAB VARCHAR2)';
end if;
commit;
end;
-- Make GC_NABID field for Next Action By Dropdown
begin
if 'NUMBER' = 'NUMBER' and length('NUMBER')>0 and length('')>0 then
execute immediate 'alter table "SERVICEMAIL6"."ETD_GUESTCARE" add(GC_NABID NUMBER(, ))';
elsif ('NUMBER' = 'NUMBER' and length('NUMBER')>0 and length('')=0) or
'NUMBER' = 'VARCHAR2' then
execute immediate 'alter table "SERVICEMAIL6"."ETD_GUESTCARE" add(GC_NABID NUMBER())';
else
execute immediate 'alter table "SERVICEMAIL6"."ETD_GUESTCARE" add(GC_NABID NUMBER)';
end if;
commit;
end;
When I run these two queries separately, there are no problems. However, when run together as shown above, Oracle gives me an error when it starts the second statement:
Error report:
ORA-06550: line 15, column 1:
PLS-00103: Encountered the symbol "BEGIN"
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
I'm assuming that this means the first statement is not terminated properly... is there anything I should put in between the statements to make it work properly?

Oracle can take one SQL statement or PL/SQL anonymous block at a time. (Unlike SQL Server that can except a batch at a time.) So, you have a couple of options.
Wrap the two anonymous blocks within another anonymous block:
begin
-- Make GC_NAB field for Next Action By Dropdown
begin
if 'VARCHAR2' = 'NUMBER' and length('VARCHAR2')>0 and length('')>0 then
execute immediate 'alter table "SERVICEMAIL6"."ETD_GUESTCARE" add(GC_NAB VARCHAR2(10, ))';
elsif ('VARCHAR2' = 'NUMBER' and length('VARCHAR2')>0 and length('')=0) or
'VARCHAR2' = 'VARCHAR2' then
execute immediate 'alter table "SERVICEMAIL6"."ETD_GUESTCARE" add(GC_NAB VARCHAR2(10))';
else
execute immediate 'alter table "SERVICEMAIL6"."ETD_GUESTCARE" add(GC_NAB VARCHAR2)';
end if;
commit;
end;
-- Make GC_NABID field for Next Action By Dropdown
begin
if 'NUMBER' = 'NUMBER' and length('NUMBER')>0 and length('')>0 then
execute immediate 'alter table "SERVICEMAIL6"."ETD_GUESTCARE" add(GC_NABID NUMBER(, ))';
elsif ('NUMBER' = 'NUMBER' and length('NUMBER')>0 and length('')=0) or
'NUMBER' = 'VARCHAR2' then
execute immediate 'alter table "SERVICEMAIL6"."ETD_GUESTCARE" add(GC_NABID NUMBER())';
else
execute immediate 'alter table "SERVICEMAIL6"."ETD_GUESTCARE" add(GC_NABID NUMBER)';
end if;
commit;
end;
end;
Tell the tool you are using to submit the PL/SQL to Oracle to send the two block seperately. How to do this will be tool specific. In SQL*PLUS, a / on a line by itself will accomplish this:
-- Make GC_NAB field for Next Action By Dropdown
begin
if 'VARCHAR2' = 'NUMBER' and length('VARCHAR2')>0 and length('')>0 then
execute immediate 'alter table "SERVICEMAIL6"."ETD_GUESTCARE" add(GC_NAB VARCHAR2(10, ))';
elsif ('VARCHAR2' = 'NUMBER' and length('VARCHAR2')>0 and length('')=0) or
'VARCHAR2' = 'VARCHAR2' then
execute immediate 'alter table "SERVICEMAIL6"."ETD_GUESTCARE" add(GC_NAB VARCHAR2(10))';
else
execute immediate 'alter table "SERVICEMAIL6"."ETD_GUESTCARE" add(GC_NAB VARCHAR2)';
end if;
commit;
end;
/
-- Make GC_NABID field for Next Action By Dropdown
begin
if 'NUMBER' = 'NUMBER' and length('NUMBER')>0 and length('')>0 then
execute immediate 'alter table "SERVICEMAIL6"."ETD_GUESTCARE" add(GC_NABID NUMBER(, ))';
elsif ('NUMBER' = 'NUMBER' and length('NUMBER')>0 and length('')=0) or
'NUMBER' = 'VARCHAR2' then
execute immediate 'alter table "SERVICEMAIL6"."ETD_GUESTCARE" add(GC_NABID NUMBER())';
else
execute immediate 'alter table "SERVICEMAIL6"."ETD_GUESTCARE" add(GC_NABID NUMBER)';
end if;
commit;
end;
/

Yes, you need a slash / on the line after each end;.

one can achieve in two ways
1) run the two blocks separately in pl/sql file.
2) in main block you can run two sbu-blocks in this way :
begin // main block
begin
..... [pl/sql commands]
......
end
begin
....... [pl/sql commands]
.......
end
end // main ends

Related

Issue with row level trigger

Can someone please let me know what mistake am I doing in the below code
Why is it giving below compilation error?
create or replace trigger emp_trigger
before insert or update or delete on emp
for each row
begin
if inserting then
dbms_output.put_line('Before inserting Old value is '|| :old.salary ||' New value : '|| :new.salary);
elsif updating then
dbms_output.put_line('Before updating Old value is '|| :old.salary ||' New value : '|| :new.salary);
elsif deleting then
dbms_output.put_line('Before deleting Old value is '|| :old.salary ||' New value : '|| :new.salary);
end if;
end;
/
Warning: Trigger created with compilation errors.
SQL> show err;
Errors for TRIGGER EMP_TRIGGER:
LINE/COL ERROR
-------- -----------------------------------------------------------------
3/59 PLS-00049: bad bind variable 'OLD.SALARY'
3/91 PLS-00049: bad bind variable 'NEW.SALARY'
5/58 PLS-00049: bad bind variable 'OLD.SALARY'
5/90 PLS-00049: bad bind variable 'NEW.SALARY'
7/58 PLS-00049: bad bind variable 'OLD.SALARY'
7/90 PLS-00049: bad bind variable 'NEW.SALARY'
Works fine now
create or replace trigger emp_trigger
before insert or update or delete on emp
for each row
begin
if inserting then
dbms_output.put_line('Before inserting Old value is '|| :old.sal ||'
New value : '|| :new.sal);
elsif updating then
dbms_output.put_line('Before updating Old value is '|| :old.sal ||'
New value : '|| :new.sal);
elsif deleting then
dbms_output.put_line('Before deleting Old value is '|| :old.sal ||'
New value : '|| :new.sal);
end if;
end;
/

create a pl/sql procedure to change the staus of the video database table

My question
Create a procedure called video_return to change the rental status for that returned copy. When the copy is successfully checked in,
you need to update the corresponding rows (records) in the VIDEO_RENTAL_RECORD and VIDEO_COPY tables.
The following are the special cases:
The value
of p_video_copy_id does not exist in the corresponding column of
the VIDEO_COPY table.
The status of that copy is not “R” (STATUS !=
'R').
The value of p_video_return_date is greater than the current date.
I have written the code but I am not sure if this code is correct or not. Please, can anyone help me out with the code? Thank you so much.
CREATE OR REPLACE PROCEDURE video_return(
p_video_copy_id NUMBER,
p_video_return_date DATE
) AS
video_copy_id number;
video_return_date date;
v_count number;
begin
select count(*) into v_count
from video
WHERE video_copy_id = p_video_copy_id;
if p_video_copy_id != video_copy_id then
Dbms_Output.PUT_LINE('Video number ' || p_video_copy_id || ' not found.');
end if;
if p_video_copy_id = video_copy_id then
update video
set p_status = 'IN'
where p_video_copy_id = video_copy_id;
IF p_video_return_date > SYSDATE THEN
update video_rental_record
set p_video_return_date = SYSDATE
where p_video_copy_id = video_copy_id
AND p_video_return_date IS NULL;
Dbms_Output.PUT_LINE('Video successfully returned and available for rental.');
END IF;
END IF;
END IF ;
END;
CREATE OR REPLACE PROCEDURE video_return
(
p_video_copy_id NUMBER,
p_video_return_date DATE
)
as
video_copy_id number;
video_return_date date;
v_count number;
begin
select count(*) into v_count from video
WHERE video_copy_id = p_video_copy_id;
if p_video_copy_id != video_copy_id then
Dbms_Output.PUT_LINE('Video number ' || p_video_copy_id || ' not found.');
end if;
if p_video_copy_id = video_copy_id then
update video set p_status = 'IN'
where p_video_copy_id = video_copy_id;
end if; -- add end if here
IF p_video_return_date > SYSDATE THEN
update video_rental_record set p_video_return_date = SYSDATE
where p_video_copy_id = video_copy_id AND p_video_return_date IS NULL;
Dbms_Output.PUT_LINE('Video successfully returned and available for rental.');
END IF;
--END IF;
--END IF ;
END;
/
There are lot of things conceptually missing here in your code. You have not initialized "video_copy_id" variable so it will be always NULL and NULL cant be compared with anything. So basically you either need to initialize the variable so change the conditions. Hope below snippet helps.
CREATE OR REPLACE PROCEDURE video_return(
p_video_copy_id NUMBER,
p_video_return_date DATE )
AS
video_copy_id NUMBER; --Not initialized always NULL
video_return_date DATE;
v_count NUMBER;
BEGIN
SELECT COUNT(*) INTO v_count FROM video WHERE video_copy_id = p_video_copy_id;
IF p_video_copy_id != nvl(video_copy_id,'some value') THEN --Cant compare anything with null
Dbms_Output.PUT_LINE('Video number ' || p_video_copy_id || ' not found.');
END IF;
IF p_video_copy_id = video_copy_id THEN
UPDATE video SET p_status = 'IN' WHERE p_video_copy_id = nvl(video_copy_id,'some value'); --Never satisfied
IF p_video_return_date > SYSDATE THEN
UPDATE video_rental_record
SET p_video_return_date = SYSDATE
WHERE p_video_copy_id = nvl(video_copy_id,'some value') --Never satisfied
AND p_video_return_date IS NULL;
Dbms_Output.PUT_LINE('Video successfully returned and available for rental.');
END IF;
END IF;
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.

Dynamic Sql, problem with binding

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;

Resources