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

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.

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;
/

Insertion using triggers by passing values

Lets say I have a table as follows--
create table employees
(
eno number(4) not null primary key,
ename varchar2(30),
zip number(5) references zipcodes,
hdate date
);
And I'm trying to create a trigger with--
CREATE OR REPLACE TRIGGER TWELVE_ONE
BEFORE INSERT OR UPDATE
ON EMPLOYEES
FOR EACH ROW
DECLARE
V_DATE VARCHAR2 (10);
BEGIN
SELECT TO_CHAR (SYSDATE, 'hh24:mi:ss') INTO V_DATE FROM DUAL;
IF (V_DATE >= '12:00:01' AND V_DATE < '13:00:00')
THEN
INSERT INTO TABLE ?????
ELSE
ROLLBACK? TERMINATE TRANSACTION?
END IF;
END;
Purpose of the trigger is to allow an insertion/update during 12:00-13:00 and prevent the insertion at any other time. The trigger construction (thanks to #Melkikun) is seems ok. However now I'm facing the following issues--
How is it possible to pass the values here? I mean lets say my create statement is:
Insert into employees Values (1, 'someone', 11111, '17-12-2015')
And lets say the time is 12:30:01 now. How would the trigger perform the insertion without knowing the values?
And lets say the time is now 13:00:1 now. How would the trigger stop/prevent the insertion?
I'm using Oracle SQL Developer 4.02.15
Many Thanks
You just have to do it the other way.
If the time is not correct,then you raise an exception, so the insert won't be done.
CREATE OR REPLACE TRIGGER TWELVE_ONE
BEFORE INSERT OR UPDATE
ON EMPLOYEES
FOR EACH ROW
DECLARE
V_DATE VARCHAR2 (10);
MyException exception;
BEGIN
SELECT TO_CHAR (SYSDATE, 'hh24:mi:ss') INTO V_DATE FROM DUAL;
IF (V_DATE < '12:00:01' OR V_DATE > '13:00:00')
THEN
raise MyException;
END IF;
EXCEPTION
When MyException then
ROLLBACK;
//output message ...
END;
How would the trigger perform the insertion without knowing the values?
The trigger knows the value thanks to :NEW and :OLD.
You normally use the terms in a trigger using :old to reference the old value and :new to reference the new value.So you will have :NEW.eno ,:NEW.ename ...
Here is an example from the Oracle documentation :
CREATE OR REPLACE TRIGGER Print_salary_changes
BEFORE DELETE OR INSERT OR UPDATE ON Emp_tab
FOR EACH ROW
WHEN (new.Empno > 0)
DECLARE
sal_diff number;
BEGIN
sal_diff := :new.sal - :old.sal;
dbms_output.put('Old salary: ' || :old.sal);
dbms_output.put(' New salary: ' || :new.sal);
dbms_output.put_line(' Difference ' || sal_diff);
END;

How i can pass column names from variables in plsql update statement

DECLARE
v_name A.TRANSACTION_TYPE%TYPE :='SALARY';
v_salary A.SALARY%TYPE := 1000;
BEGIN
update A set v_name= v_salary where EMPID = 517;
-- PL/SQL: ORA-00904: "v_name": invalid identifier
--update A set SALARY = 1000 where EMPID = 517;
END;
/
My idea is to update table columns , but these column names are stored in variable. Is there any way to pass column names from variable ? Is there any options apart from Execute Immediate
Not sure if this will work in your situation, but I've written solutions where I wrote a script in SQLPlus and it "wrote" (using dbms_output.put_line or even just prompt) another script that did queries, and the columns/tables in those queries was determined by the logic in the SQLPlus script. Then I would execute as a script the output from my first script, and it would execute dynamically generated queries without ever needing execute immediate.
The following idea may work for multiple columns that are typed the same... As written, it will update all columns every time for a given record, but only the column specified by v_name will be changed to the value set in v_value; the other columns are simply updated to their existing value. The idea can be played with using DECODE, NVL or other similar conditional operators.
declare
v_name varchar2(20):= 'SAL';
v_value emptest.sal%TYPE := 5000;
begin
update emptest
set sal = ( select case when v_name = 'SAL' then v_value else sal end from dual),
comm = ( select case when v_name = 'COMM' then v_value else comm end from dual)
where empno = 7369;
commit;
end;

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