Unable to dynamically start sequence - plsql

Based on this example, I created this code:
DECLARE
new_employee_id INTEGER;
BEGIN
SELECT MAX(EMP_ID) + 1 INTO new_employee_id FROM EMPLOYEE;
EXECUTE IMMEDIATE 'CREATE OR REPLACE SEQUENCE primary_key_seq START WITH ' || new_employee_id || ' INCREMENT BY 1';
END;
/
OBS: perhaps using a sequence to auto increment the primary key of a table doesn't make much sense, but this is a school exercise and that's what we're supposed to do, so please disregard that aspect.
This is the error I have:
ERROR AT LINE 1
ORA-00922: missing or invalid option
ORA-06512: at line 5
What could be wrong?

There is no CREATE OR REPLACE SEQUENCE option, so you must use the CREATE SEQUENCE Statement and the a DROP statement if you need to drop it first.
DECLARE
new_employee_id INTEGER;
BEGIN
SELECT MAX(EMP_ID) + 1 INTO new_employee_id FROM EMPLOYEE;
EXECUTE IMMEDIATE 'CREATE SEQUENCE primary_key_seq START WITH ' || new_employee_id || ' INCREMENT BY 1';
END;
/

there is no REPLACE in create sequence command check documentation (wich is always a good idea ;-)
should be
DECLARE
new_employee_id INTEGER;
BEGIN
SELECT MAX(EMP_ID) + 1 INTO new_employee_id FROM EMPLOYEE;
EXECUTE IMMEDIATE 'CREATE SEQUENCE primary_key_seq START WITH ' || new_employee_id || ' INCREMENT BY 1';
END;
/

This question begs another question - why are you trying to drop and re-add a sequence? You should never need to do this. Create the sequence once:
CREATE SEQUENCE PRIMARY_KEY_SEQ
MINVALUE 1
MAXVALUE 9999999999999999999999999999
START WITH 1
INCREMENT BY 1
NOCACHE;
Then, use it in your code:
DECLARE
new_employee_id INTEGER;
BEGIN
new_employee_id := PRIMARY_KEY_SEQ.NEXTVAL;
INSERT INTO SOME_TABLE_MAYBE_EMPLOYEES
(ID, WHATEVER, WHATEVER_ELSE)
VALUES
(new_employee_id, 'WHATEVER', 'WHATEVER_ELSE');
END;
The whole purpose of the sequence is to provide unique, non-repeating values. Going out to the table, grabbing the MAX(ID), and recreating the sequence to start from there is sort of backwards from the way a sequence should be used. Create a sequence once, then use it many times.
Hopefully this helps.
Share and enjoy.

Related

Oracle trigger execution on a particular condition

My requirement is that I have a table where there are 4 columns(val1,val1_date,new_val1,new_val1_date) in it.
The issue is that when new_val1 gets updated along with new_val1_date,I need to update columns val1,val1_date accordingly.
For that I have created a function.
Now when new_val1_date is equal to sysdate then I want to execute the trigger.
My trigger is not giving me proper result.
Can anyone help me in that.
create or replace TRIGGER MY_Trigger
AFTER INSERT OR UPDATE ON my_table
FOR EACH ROW
WHEN (TO_DATE(NEW.new_val1_date,'dd/mon/yyyy')<=TO_DATE(sysdate,'dd/mon/yyyy'))
declare
V_CD_ERROR NUMBER;
V_DS_ERROR VARCHAR2(500);
begin
My_UpdateProc(V_CD_ERROR,V_DS_ERROR);
DBMS_OUTPUT.PUT_LINE('V_CD_ERROR: ' || V_CD_ERROR || ' V_DS_ERROR ' || V_DS_ERROR);
end;
Oracle Date columns store the timestamp, so unless your inserted value matches sysdate down to the second, it won't have the expected result.
You need to "trunc" the dates so the timestamp is set to midnight for both values. Then it will evaluate based on the date.
Also, the evaluation should be done inside the begin/end block of the trigger.
create or replace TRIGGER MY_Trigger
AFTER INSERT OR UPDATE ON my_table
FOR EACH ROW
declare
V_CD_ERROR NUMBER;
V_DS_ERROR VARCHAR2(500);
begin
if (trunc(NEW.new_val1_date) = trunc(sysdate)) then
My_UpdateProc(V_CD_ERROR,V_DS_ERROR);
DBMS_OUTPUT.PUT_LINE('V_CD_ERROR: ' || V_CD_ERROR || ' V_DS_ERROR ' || V_DS_ERROR);
end if;
end;

I'm having trouble writing a cursor/loop. I'm not sure why it's not working

My code is here. I keep getting errors for the select statement. I've already created a waitlist table and a sequence. I inserted values into waitlist, however; I had to get the sname from the students table since waitlist does not have sname in the table. I'm trying to display RankingSid, Snum, sname, time(such as 1 pm or 2 pm).
create or replace procedure getWaiting(
p_callnum waitlist.callnum%type) as
cursor cwaiting is
select RankingSid, waitlist.snum, students.sname, to_char(time, 'hh AM')time
from waitlist, students
where p_callnum=callnum
and waitlist.snum=students.snum;
begin
For EachStudent in cwaiting loop
insert into TestTable values (EachStudent.RankingSid, Eachstudent.snum, EachStudent.sname, EachStudent.time);
dbms_output.put_line(eachstudent.rankingsid || eachstudent.snum || eachstudent.sname, eachstudent.time);
end loop;
end;
/
There are a number of syntax errors in your code, the biggest being your insert statement you need to reference your cursor variable for the insert in the same way that you did for the dbms_output. I do not have your table definitions to test the code but the below should be pretty close to what you need.
create or replace procedure getWaiting(
p_callnum waitlist.callnum%type) as
cursor cwaiting is
select RankingSid, waitlist.snum, students.sname, to_char(time, 'hh AM')time
from waitlist, students
where p_callnum=callnum
and waitlist.snum=students.snum;
begin
For EachStudent in cwaiting loop
insert into TestTable values (EachStudent.RankingSid, Eachstudent.snum, EachStudent.sname, EachStudent.time);
dbms_output.put_line(eachstudent.rankingsid || eachstudent.snum || eachstudent.sname || eachstudent.time);
end loop;
end;
/
I did it another way and would like to know how to change it..insert table wasn't working the other way. I was wondering if i'd have to create instead of inserting
create or replace procedure getWaiting(
p_callnum waitlist.callnum%type) as
begin
For eachRec in (select waitlist.rankingsid, students.snum, students.sname, to_char(time, 'hh:mi:ss AM') RequestedTime
from students, waitlist
where p_callnum=callnum
and students.snum=waitlist.snum
order by rankingsid)
Loop
dbms_output.put_line('Rank Number '|| eachRec.rankingsid ||' Student Name ' ||eachRec.sname ||' Student Number ' || eachRec.snum ||' Wait List Date ' || eachRec.RequestedTime);
end Loop;
end;
/

How to place a plsql block inside a sequence

I am trying to create a user generated sequence. According to usual syntax of oracle sequence we can start with a number and increment a value.
Is there a method to write a plsql block (declare begin end) inside a sequence and generate my own sequnce.
example : ABC001
When i call the next val of sequence , the value should be ABC002
PLEASE CLEAR FIRST WHAT YOU EXACTLY WANT TO ASK.
If you are asking HOW TO DYNAMICALLY CREATE SEQUENCE USING PL/SQL, then check below.
Simplest way.
DECLARE
SQL_S VARCHAR2(100);
BEGIN
SQL_S := 'CREATE SEQUENCE SQN_NAME INCREMENT BY 1 START WITH 1';
EXECUTE IMMEDIATE SQL_S;
END;
/
If you want to dynamically create sequence with some DYNAMIC name as argument passed to procedure, then it will be like
CREATE OR REPLACE PROCEDURE DYNAMIC_SQN (ARG IN VARCHAR2) IS
SQL_S VARCHAR2(100);
PARAM1 VARCHAR2(20);
BEGIN
PARAM1 := 'SQN_NAME_' || ARG;
SQL_S := 'CREATE SEQUENCE ' || PARAM1 || ' INCREMENT BY 1 START WITH 1';
EXECUTE IMMEDIATE SQL_S;
END;
/
And if you simply want to insert in to any column, and create the PK using it in addition to some String, then
INSERT INTO TABLE_T VALUES('ABC'|| SEQUENCE_NAME.nextval, OTHER_VALUES);
It will still give you values like : ABC1, ABC2, .... ABC12, ABC13, .... ABC99, ABC100 and so on...
Considering the sample example you have given i m writing the following code
create your sequence, then
insert into seq values('ABC'||YOURSEQUENCENAME.nextval,YOUR_VALUE);

PL/SQL - column value is updated as 0 instead of numeric value

Declare
v_cnt varchar2(20);
v_cnd varchar2(20);
v_total varchar2(20);
begin
select count(emp_id) into v_cnt from emp1;
select count(emp_id) into v_cnd from emp2;
v_total:=v_cnt+v_cnd;
dbms_output.put_line('before');
dbms_output.put_line(v_total);
update emp3 set total_emp=v_total where dept_no=40;
commit;
dbms_output.put_line('after');
dbms_output.put_line(v_total);
end;
In the above program, value for the column total_emp is getting updated as 0 instead of numeric value.
However, when I use dbms_output statement to print the value, for both the cases, before and after , I'm getting the numeric value for the variable v_total.
v_total value is not getting updated to column value in table.
table column definition for total_emp is varchar2(20).
Also, I tried to hard code value for total_emp column in the above statement and it worked.
So, the problem is variable value when used in the update statement it's not getting updated to column.
Please help me.
The variables you declared should be of type NUMBER instead of VARCHAR2, as you intend to use them in calculations. I also suggest you add an exception handler to report any errors which may occur. It's also a good idea to show how many rows were affected by your update. You might want to rewrite your code as:
Declare
v_cnt NUMBER;
v_cnd NUMBER;
v_total NUMBER;
begin
select count(emp_id)
into v_cnt
from emp1;
select count(emp_id)
into v_cnd
from emp2;
v_total:=v_cnt+v_cnd;
dbms_output.put_line('before');
dbms_output.put_line(v_total);
update emp3
set total_emp=v_total
where dept_no=40;
DBMS_OUTPUT.PUT_LINE('Number of rows updated=' || SQL%ROWCOUNT);
commit;
dbms_output.put_line('after');
dbms_output.put_line(v_total);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Exception: ' || SQLCODE || ' ' || SQLERRM);
ROLLBACK;
end;
Share and enjoy.

PL/SQL Inserting 1 row for each result in a select

I am writing a PL/SQL Procedure that performs a select based on input variables and then inserts a row for each result in the select. I am having trouble debugging what is wrong with my query due my newness to PL/SQL. I know this must be easy, but I am stuck here for some reason. Thanks for your help!
CREATE OR REPLACE PROCEDURE setup_name_map(ranking_id IN NUMBER, class_string IN VARCHAR2)
IS
BEGIN
FOR rec IN (SELECT NAME_ID FROM PRODUCT_NAMES WHERE NAME = class_string)
LOOP
EXECUTE IMMEDIATE 'INSERT INTO NAME_RANKING (NAME_ID, RANKING_ID) VALUES (' || rec.NAME_ID || ', ' || ranking_id || ')';
END LOOP;
END;
According to the Oracle Developer Compiler... 'NAME_ID' is an invalid identifier. I've tried putting it in quotes but no dice. It also complains that loop index variables 'REC' use is invalid. Any help is much appreciated.
There is no need for dynamic SQL here:
BEGIN
FOR rec IN (SELECT NAME_ID FROM PRODUCT_NAMES
WHERE NAME = class_string)
LOOP
INSERT INTO NAME_RANKING (NAME_ID, RANKING_ID)
VALUES (rec.NAME_ID, ranking_id);
END LOOP;
END;
Better still you can avoid a slow row-by-row cursor approach like this:
BEGIN
INSERT INTO NAME_RANKING (NAME_ID, RANKING_ID)
SELECT NAME_ID, ranking_id FROM PRODUCT_NAMES
WHERE NAME = class_string;
END;
If you really did need the dynamic SQL you should not be concatenating values into it, but using bind variables:
BEGIN
FOR rec IN (SELECT NAME_ID FROM PRODUCT_NAMES
WHERE NAME = class_string)
LOOP
EXECUTE IMMEDIATE 'INSERT INTO NAME_RANKING
(NAME_ID, RANKING_ID) VALUES (:b1, :b2)
USING rec.NAME_ID, ranking_id;
END LOOP;
END;

Resources