Oracle mutating tables - oracle

I have this procedure which calculates the total amount paid for a car and determines if the car status can be changed to 'SOLD' if the amount is equal to the price.
I know the problem is the query in car_payment but I can't find other way to make the sum of the amount, can anybody help me, please?
create or replace trigger tr_paid_car
before insert
or update of amount
on car_payment
for each row
declare
v_amount number;
v_car_status_id car_status.car_status_id%type;
v_price car.price%type;
begin
select sum(amount)
into v_amount
from car_payment
where car_id = :new.car_id;
if inserting then
v_amount := v_amount + :new.amount;
elsif updating then
v_amount := v_amount + :new.amount - :old.amount;
end if;
select price
into v_price
from car
where car_id = :new.car_id;
if v_amount >= v_price then
select car_status_id
into v_car_status_id
from car_status
where description = 'SOLD';
update car
set car_status_id = v_car_status_id
where car_id = :new.car_id;
end if;
end;
/

Create a another function called: GET_CAR_PAY_AMT as below.
CREATE OR REPLACE FUNCTION GET_CAR_PAY_AMT(p_car_id car_payment.car_id%type) return number
as
pragma autonomous_transaction;
x number;
begin
select sum(amount)
into x
from car_payment
where car_id = p_car_id;
return x;
end GET_CAR_PAY_AMT;
Now use function GET_CAR_PAY_AMT instead of your SELECT statement in the trigger as below:
Replace below SQL:
select sum(amount)
into v_amount
from car_payment
where car_id = :new.car_id;
With:
v_amount := GET_CAR_PAY_AMT(:new.car_id);

Related

Count is not working in trigger using condition

Hi could you please suggest I am trying to check if count =2
When Condition meet (DA.matr_ID = '478') or (DA.matr_ID = '40') then
insert into table, but in any condition like (DA.matr_ID = '479') it insert the data which is wrong
CREATE OR REPLACE TRIGGER DEVICE_TMP_TR
AFTER INSERT OR UPDATE ON DEVICE_ATTRIBUTES_TMP
REFERENCING OLD AS old NEW AS new
FOR EACH ROW
DECLARE
pragma autonomous_transaction;
V_COUNT NUMBER;
BEGIN
SELECT COUNT(*)
INTO V_COUNT
FROM DEVICE_ATTRIBUTES_TMP DA
WHERE DA.DVS_ID = :new.DVS_ID
AND (DA.matr_ID = '40' or DA.matr_ID = '478');
IF V_COUNT = 2 THEN
INSERT Into APP_DELETED_TMP
(sdmid,appid,devis,des_nr,creation_date,creation_user,ant_id)
VALUES
('121213', '23', '45','63',SYSDATE,'hhdhSH',21);
COMMIT;
ELSE
RETURN;
END IF;
END;

Oracle SQL%ROWCOUNT statement always return 1

I have a simple table USERS in Oracle with 2 columns ID and USERNAME.
ID is the primary key and auto incremented using a trigger.
I am inserting or updating records using a procedure like this
CREATE OR REPLACE PROCEDURE SaveUser(UID NUMBER, UN VARCHAR2, Row_Count OUT NUMBER) IS
BEGIN
IF(UID > 0) THEN
UPDATE USERS SET USERNAME = UN WHERE ID = UID;
ELSE
INSERT INTO USERS(USERNAME) VALUES(UN);
END IF;
Row_Count := SQL%ROWCOUNT;
END;
I am calling the procedure like this:
VARIABLE Row_Count NUMBER;
EXEC SaveUser(50, 'Username_1', Row_Count);
PRINT Row_Count;
The issue is I am passing 50 as the first parameter, but in the table there is no row with ID 50. But I am getting 1 as the result. Even if the row is not updated, SQL%ROWCOUNT statement returns 1. Can anyone help me to fix this?
The above code is simplified one and the exact code is here
CREATE OR REPLACE PROCEDURE SaveEmployee(ID NUMBER, User_Name VARCHAR2, Emp_Password VARCHAR2, Emp_Full_Name VARCHAR2, Emp_Date_Of_Birth DATE, Emp_Gender_ID NUMBER, Emp_Work_Type_ID NUMBER, Emp_Salary FLOAT, Emp_Email VARCHAR2, Row_Count OUT NUMBER) IS
Username_Row_Count NUMBER := 0;
Email_Row_Count NUMBER := 0;
BEGIN
IF(ID > 0) THEN
SELECT COUNT(1) INTO Username_Row_Count FROM EMPLOYEES WHERE LOWER(USERNAME) = LOWER(User_Name) AND EMPLOYEE_ID <> ID;
SELECT COUNT(1) INTO Email_Row_Count FROM EMPLOYEES WHERE LOWER(EMAIL) = LOWER(Emp_Email) AND EMPLOYEE_ID <> ID;
IF(Username_Row_Count = 0 AND Email_Row_Count = 0) THEN
UPDATE EMPLOYEES
SET USERNAME = LOWER(User_Name), PASSWORD = Emp_Password, FULL_NAME = Emp_Full_Name, DATE_OF_BIRTH = Emp_Date_Of_Birth, GENDER_ID = Emp_Gender_ID, WORK_TYPE_ID = Emp_Work_Type_ID, SALARY = Emp_Salary, EMAIL = LOWER(Emp_Email)
WHERE EMPLOYEE_ID = ID;
END IF;
ELSE
SELECT COUNT(1) INTO Username_Row_Count FROM EMPLOYEES WHERE LOWER(USERNAME) = LOWER(User_Name);
SELECT COUNT(1) INTO Email_Row_Count FROM EMPLOYEES WHERE LOWER(EMAIL) = LOWER(Emp_Email);
IF(Username_Row_Count = 0 AND Email_Row_Count = 0) THEN
INSERT INTO EMPLOYEES(USERNAME, PASSWORD, FULL_NAME, DATE_OF_BIRTH, GENDER_ID, WORK_TYPE_ID, SALARY, EMAIL, LOGIN_ATTEMPTS)
VALUES(LOWER(User_Name), Emp_Password, Emp_Full_Name, Emp_Date_Of_Birth, Emp_Gender_ID, Emp_Work_Type_ID, Emp_Salary, LOWER(Emp_Email), 0);
END IF;
END IF;
Row_Count := SQL%ROWCOUNT;
END;
I can't reproduce what you are saying:
SQL> select * from users;
no rows selected
SQL> declare
2 uid number := 50;
3 begin
4 if uid > 0 then
5 update users set username = '&&un' where id = uid;
6 else
7 insert into users (username) values ('&&un');
8 end if;
9 dbms_output.put_line(sql%rowcount);
10 end;
11 /
Enter value for un: 50
0 --> this is SQL%ROWCOUNT
PL/SQL procedure successfully completed.
SQL>
Code you posted is invalid (there's no NUBER datatype). It would help if you posted something that actually works, because - the way you put it - we can't be sure that what you claim to be true really is true. Please, copy/paste your own SQL*Plus session (just like I did) so that we'd see what you really have and how Oracle responded.
Add SQL%ROWCOUNT after the update to get the update count
UPDATE EMPLOYEES
SET USERNAME = LOWER(User_Name), PASSWORD = Emp_Password, FULL_NAME = Emp_Full_Name, DATE_OF_BIRTH = Emp_Date_Of_Birth, GENDER_ID = Emp_Gender_ID, WORK_TYPE_ID = Emp_Work_Type_ID, SALARY = Emp_Salary, EMAIL = LOWER(Emp_Email)
WHERE EMPLOYEE_ID = ID;
Row_Count := SQL%ROWCOUNT;
Now it's more clear.
This code:
SELECT COUNT(1) INTO Username_Row_Count FROM EMPLOYEES WHERE LOWER(USERNAME) = LOWER(User_Name) AND EMPLOYEE_ID <> ID;
SELECT COUNT(1) INTO Email_Row_Count FROM EMPLOYEES WHERE LOWER(EMAIL) = LOWER(Emp_Email) AND EMPLOYEE_ID <> ID;
must update the values Username_Row_Count and Email_Row_Count, so that the condition
IF(Username_Row_Count = 0 AND Email_Row_Count = 0) THEN
is always false. And the update is never executed. As the result, in your Row_Count variable you get the result of the last select, which is 1 row.

Passing data when query returns value and No "EXCEPTION WHEN NO_DATA_FOUND THEN" (Oracle 11g)

I have created a procedure for updating my t_ritm table. First I have select rrcd_qnty (which is my product quantity) of a product id from t_rrcd table. Then I update the rrcd_qnty value in t_ritm table.
Here is my procedure:
procedure update_ritm_new_rate(p_oid in varchar2, p_ritm_rate in varchar2, p_euser in varchar2)
is
nrate varchar2(4);
begin
SELECT rrcd_rate into nrate
FROM (select oid, t_rrcd.rrcd_rate
from t_rrcd
where rrcd_ritm= p_oid
ORDER BY oid DESC )
WHERE rownum <= 1
ORDER BY rownum DESC ;
EXCEPTION
WHEN NO_DATA_FOUND THEN nrate := 0;
update t_ritm
set ritm_rate = nrate, euser = p_euser, edat = sysdate
where oid = p_oid;
commit;
end update_ritm_new_rate;
Some of my product id Quantity was null. so I was getting No_Data_Found error. But when and which product id has Quantity value they were successfully updating. For avoiding No_Data_Found I used EXCEPTION WHEN NO_DATA_FOUND THEN nrate := 0; which solved my no_Data_Found error. But when product id has quantity value they were not updating.
I had search lot of for this issue but not get good solution. What should be the best practice for avoiding No_Data_Found error? Could I pass my value if I don't get any No_Data_Found error?
thank in advance
That's because - if your SELECT returns something, it never reaches UPDATE as it is hidden behind the EXCEPTION handler.
Therefore, enclose it (SELECT) into its own BEGIN-END block, and put UPDATE out of it so that it is executed with whichever NRATE value is used.
PROCEDURE update_ritm_new_rate (p_oid IN VARCHAR2,
p_ritm_rate IN VARCHAR2,
p_euser IN VARCHAR2)
IS
nrate VARCHAR2 (4);
BEGIN
BEGIN --> this
SELECT rrcd_rate
INTO nrate
FROM ( SELECT oid, t_rrcd.rrcd_rate
FROM t_rrcd
WHERE rrcd_ritm = p_oid
ORDER BY oid DESC)
WHERE ROWNUM <= 1
ORDER BY ROWNUM DESC;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
nrate := 0;
END; --> this
UPDATE t_ritm
SET ritm_rate = nrate, euser = p_euser, edat = SYSDATE
WHERE oid = p_oid;
COMMIT;
END update_ritm_new_rate;
I have fixed the issue by adding EXCEPTION WHEN NO_DATA_FOUND THEN nrate := 0; after the update query.
procedure update_ritm_new_rate(p_oid in varchar2, p_ritm_rate in varchar2, p_euser in varchar2)
is
nrate varchar2(4);
begin
SELECT rrcd_rate into nrate FROM (select oid, t_rrcd.rrcd_rate from t_rrcd where rrcd_ritm= p_oid ORDER BY oid DESC )
WHERE rownum <= 1 ORDER BY rownum DESC ;
update t_ritm set ritm_rate = nrate, euser = p_euser, edat = sysdate where oid = p_oid;
commit;
EXCEPTION WHEN NO_DATA_FOUND THEN nrate := 0;
end update_ritm_new_rate;

Difficulty compiling an AFTER INSERT OR UPDATE trigger

I have an EMPLOYEE table with SALARY field. I'm using Oracle SQL developer. I want to write a trigger so that when someone update salary in EMPLOYEE table, it will update Salary field in EMPLOYEE_SALARIES table as low, medium, high. Here's the second table.
CREATE TABLE Employee_Salaries(
Ssn CHAR(9) NOT NULL,
Salary VARCHAR(10),
Log_Date DATE
);
Here's the trigger and procedure to update the Salary field to low, middle or high.
CREATE OR REPLACE PROCEDURE salaryType(x IN NUMBER, y OUT VARCHAR) IS
BEGIN
IF x >= 60000 THEN y := 'HIGH';
ELSIF (x >= 40000 AND x <= 60000) THEN y := 'MEDIUM';
ELSE y := 'LOW';
END IF;
END salaryType;
/
I get compiler error on this trigger. Please tell me what I did wrong or am I missing something.
CREATE OR REPLACE TRIGGER salary1
AFTER INSERT OR UPDATE ON Employee
FOR EACH ROW
BEGIN
DECLARE
salaryRank VARCHAR(10) := ' ';
salaryType(:new.Salary, salaryRank);
INSERT INTO Employee_Salaries(Ssn, Salary, Log_Date) VALUES (:new.Ssn, salaryRank, SYSDATE);
END;
/
Declaration Part is at wrong place(should be before BEGIN and just after FOR EACH ROW statement of TRIGGER's header), Make it as the following :
CREATE OR REPLACE TRIGGER salary1
AFTER INSERT OR UPDATE ON Employee
FOR EACH ROW
DECLARE
salaryRank VARCHAR(10) := ' ';
BEGIN
salaryType(:new.Salary, salaryRank);
INSERT INTO Employee_Salaries(Ssn, Salary, Log_Date) VALUES (:new.Ssn, salaryRank, SYSDATE);
END;
The keyword BEGIN in the trigger is in the wrong place. It should come after the DEFINE block; that is, after you declare salaryrank and before you invoke the procedure.

Exact fetch returns more than requested number of rows

I'm trying to create a procedure to pass in the customer number and return the number of purchases and total value for purchases within the last year. If there are no purchases, return zero for number and total and also return the number of contacts the salesmen had with that customer in the last year.
I'm calling it as follows:
DECLARE
a_Var NUMBER;
b_Var NUMBER;
C_Var NUMBER;
D_Var NUMBER;
BEGIN
three_pr(001116,a_Var, b_Var);
IF a_Var > 0 THEN
DBMS_OUTPUT.PUT_LINE('the number of purchases :' || a_Var);
DBMS_OUTPUT.PUT_LINE('the total value of purchase :' || b_Var);
ELSE
SELECT ContactID,Count(contactID)
INTO
C_Var,D_Var
FROM DD_Contacts
WHERE DateofContact between to_date ('2012/01/01', 'yyyy/mm/dd')
AND to_date ('2012/12/31', 'yyyy/mm/dd')
Group By ContactID;
DBMS_OUTPUT.PUT_LINE (C_Var||D_Var);
END IF;
END;
/
When using the above code I get the error:
ORA-01422: exact fetch returns more than requested number of rows ORA-06512: at line 16
and here's the procedure:
CREATE or REPLACE PROCEDURE three_pr
(par_CustomerID IN NUMBER, par_sumpurchase OUT Number,par_totalvalue OUT Number)
IS
BEGIN
SELECT
COUNT(O.OrderID),SUM(Price*Quantity)
INTO par_sumpurchase,par_totalvalue
FROM DD_Orders O JOIN DD_OrderLine OL ON O.OrderID = OL.OrderID
WHERE DatePurchase between to_date ('2012/01/01', 'yyyy/mm/dd')
AND to_date ('2012/12/31', 'yyyy/mm/dd')
AND CustomerID = par_CustomerID;
END;
/
The procedure three_pr does not correctly handle the NO_DATA_FOUND exception when the query does not return results.
CREATE or REPLACE PROCEDURE three_pr
(par_CustomerID IN NUMBER, par_sumpurchase OUT Number,par_totalvalue OUT Number)
IS
BEGIN
BEGIN
SELECT
COUNT(O.OrderID),SUM(Price*Quantity)
INTO par_sumpurchase,par_totalvalue
FROM DD_Orders O JOIN DD_OrderLine OL ON O.OrderID = OL.OrderID
WHERE DatePurchase between to_date ('2012/01/01', 'yyyy/mm/dd')
AND to_date ('2012/12/31', 'yyyy/mm/dd')
AND CustomerID = par_CustomerID;
EXCEPTION
WHEN NO_DATA_FOUND THEN
par_sumpurchase := 0;
par_totalvalue := 0;
END;
END;
/

Resources