mgr table is the table with employeessn, mgrssn, and salary. It takes data from employee table and department table.
create table mgr as
select ssn, mgrssn, salary
from Employee E
join Department D
on E.Dno = D.Dno;
select * from mgr;
Here is my trigger
create or replace trigger check_sal
for insert or update on employee
compound trigger
type t_ch_tab is table of mgr%rowtype;
g_ch_tab t_ch_tab := t_ch_tab();
after each row is
begin
g_ch_tab.extend;
g_ch_tab(g_ch_tab.last).ssn := :new.ssn;
g_ch_tab(g_ch_tab.last).mgrssn := :new.mgrssn;
g_ch_tab(g_ch_tab.last).salary := :new.salary;
end after each row;
after statement is
l_sal employee.sal%type;
begin
for i in g_ch_tab.first .. g_ch_tab.last loop
select e.salary
into l_salary
from employee e
where e.ssn = g_ch_tab(i).mgrssn;
if g_ch_tab(i).salary > l_salary then
raise_application_error(-20001, 'Employee''s salary can not be higher than manager''s salary');
end if;
end loop;
end after statement;
end check_sal;
I am getting the following error.
Error(17,45): PLS-00049: bad bind variable 'NEW.MGRSSN'
create table department (
mgrssn varchar2(100),
dno number);
create table employee (
ssn varchar2(100),
salary number,
dno number
);
create table mgr as select ssn,mgrssn,salary,e.dno from Employee E, Department D where E.Dno = D.Dno;
create or replace trigger check_sal
for insert or update on employee
compound trigger
type t_ch_tab is table of mgr%rowtype;
g_ch_tab t_ch_tab := t_ch_tab();
after each row is
begin
g_ch_tab.extend;
g_ch_tab(g_ch_tab.last).ssn := :new.ssn;
-- g_ch_tab(g_ch_tab.last).mgrssn := :new.mgrssn;
g_ch_tab(g_ch_tab.last).salary := :new.salary;
g_ch_tab(g_ch_tab.last).dno := :new.dno;
end after each row;
after statement is
l_salary employee.salary%type;
begin
for i in g_ch_tab.first .. g_ch_tab.last loop
select e.salary
into l_salary
from employee e, department d
-- where e.ssn = g_ch_tab(i).mgrssn;
where e.ssn = d.mgrssn
and e.dno = g_ch_tab(i).dno;
if g_ch_tab(i).salary > l_salary then
raise_application_error(-20001, 'Employee''s salary can not be higher than manager''s salary');
end if;
end loop;
end after statement;
end check_sal;
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;
I want to perform an update on a huge table on a table like this (I now it's not best practise):
TARGET_TABLE (
TICKET_ID number,
product_id number,
NET number(15,2),
VAT number(15,2));
http://sqlfiddle.com/#!4/d39ed/3
Aim: UPDATE TARGET_TABLE set NET=VAT, VAT=NET
I came up with a BULK UPDATE, but I get an ORA-00913: "To many values" at line 43 which I can't explain. Also, I don't know how to update two rows at once in that variant.
Could anyone help out?
DECLARE
-- new data
CURSOR new_data_cur IS
select
a.rowid,
a.TICKET_ID,
a.product_id,
b.NET,
b.VAT
from TARGET_TABLE a
join TARGET_TABLE_COPY b
on ( a.TICKET_ID=b.TICKET_ID AND a.product_id =b.product_id ) ;
TYPE new_data_type IS TABLE OF new_data_cur%rowtype INDEX BY PLS_INTEGER;
new_data_tab new_data_type;
TYPE row_id_type IS TABLE OF ROWID INDEX BY PLS_INTEGER;
row_id_tab row_id_type;
TYPE rt_update_cols IS RECORD (
NET TARGET_TABLE.NET%TYPE
-- VAT TARGET_TABLE.VAT%TYPE
);
TYPE update_cols_type IS
TABLE OF rt_update_cols INDEX BY PLS_INTEGER;
update_cols_tab1 update_cols_type;
--update_cols_tab2 update_cols_type;
dml_errors EXCEPTION;
PRAGMA exception_init ( dml_errors,-24381 );
BEGIN
OPEN new_data_cur;
LOOP
FETCH new_data_cur BULK COLLECT INTO new_data_tab LIMIT 50000;
EXIT WHEN new_data_tab.count=0;
FOR i IN new_data_tab.first..new_data_tab.last LOOP
row_id_tab(i) := new_data_tab(i).rowid;
update_cols_tab1(i).NET := new_data_tab(i).VAT;
-- update_cols_tab2(i).VAT := new_data_tab(i).NET;
END LOOP;
FORALL i IN new_data_tab.first..new_data_tab.last SAVE EXCEPTIONS # ORA-00913: To many values
UPDATE TARGET_TABLE
-- SET row = update_cols_tab(i)
SET row = update_cols_tab1(i)
-- row = update_cols_tab2(i)
WHERE ROWID = row_id_tab(i);
COMMIT;
EXIT WHEN new_data_tab.count=0;
END LOOP;
COMMIT;
CLOSE new_data_cur;
EXCEPTION
WHEN dml_errors THEN
FOR i IN 1..SQL%bulk_exceptions.count LOOP
dbms_output.put_line('Some error occured');
END LOOP;
END;
I believe you don't need an extra cursor where you are swapping the values
FOR i IN new_data_tab.first..new_data_tab.last LOOP
row_id_tab(i) := new_data_tab(i).rowid;
update_cols_tab1(i).NET := new_data_tab(i).VAT;
-- update_cols_tab2(i).VAT := new_data_tab(i).NET;
END LOOP;
So you code will use these values in your bulk update
DECLARE
-- new data
CURSOR new_data_cur IS
select
a.rowid,
a.TICKET_ID,
a.product_id,
b.NET,
b.VAT
from TARGET_TABLE a
join TARGET_TABLE_COPY b
on ( a.TICKET_ID=b.TICKET_ID AND a.product_id =b.product_id ) ;
TYPE new_data_type IS TABLE OF new_data_cur%rowtype INDEX BY PLS_INTEGER;
new_data_tab new_data_type;
TYPE row_id_type IS TABLE OF ROWID INDEX BY PLS_INTEGER;
row_id_tab row_id_type;
TYPE rt_update_cols IS RECORD (
NET TARGET_TABLE.NET%TYPE
-- VAT TARGET_TABLE.VAT%TYPE
);
TYPE update_cols_type IS
TABLE OF rt_update_cols INDEX BY PLS_INTEGER;
update_cols_tab1 update_cols_type;
--update_cols_tab2 update_cols_type;
dml_errors EXCEPTION;
PRAGMA exception_init ( dml_errors,-24381 );
BEGIN
OPEN new_data_cur;
LOOP
FETCH new_data_cur BULK COLLECT INTO new_data_tab LIMIT 50000;
EXIT WHEN new_data_tab.count=0;
FORALL i IN new_data_tab.first..new_data_tab.last SAVE EXCEPTIONS # ORA-00913: To many values
UPDATE TARGET_TABLE
-- SET row = update_cols_tab(i)
-- SET row = update_cols_tab1(i)
-- row = update_cols_tab2(i)
NET = update_cols_tab1(i).VAT
VAT = update_cols_tab1(i).NET
WHERE ROWID = row_id_tab(i);
COMMIT;
EXIT WHEN new_data_tab.count=0;
END LOOP;
COMMIT;
CLOSE new_data_cur;
EXCEPTION
WHEN dml_errors THEN
FOR i IN 1..SQL%bulk_exceptions.count LOOP
dbms_output.put_line('Some error occured');
END LOOP;
END;
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);
I have a Stored procedure in PLSQL which Inserts and Updates records on the basis of some condition.
Now here the issue is. While Inserting the record for the first time, it inserts records properly as required but
while updating it doesn't updates the record of the table.
Below is SP
PROCEDURE INSERT_INTO_VSAT_MST_DATA
(
P_SAPID IN NVARCHAR2,
P_CIRCLE IN NVARCHAR2,
P_CANDIDATEID IN NVARCHAR2,
P_SITEID IN NVARCHAR2,
P_PRIORITYID IN NVARCHAR2,
P_SITENAME IN NVARCHAR2,
P_LATITUDE IN NVARCHAR2,
P_LONGITUDE IN NVARCHAR2,
P_CONTACT_DETAILS IN CLOB,
P_SITETYPE IN NVARCHAR2,
P_SITE_PLOT_DIMENSION IN NUMBER,
P_TECHNOLOGY IN NVARCHAR2
)
AS
V_COUNT NUMBER:=0;
V_PANAROMICIMG_COUNT NUMBER:=0;
V_SATELLITEIMG_COUNT NUMBER:=0;
V_SITEPLOTIMG_COUNT NUMBER:=0;
V_VSAT_DETAIL_ID NUMBER:=0;
BEGIN
SELECT COUNT(VSAT_DETAIL_ID) INTO V_COUNT FROM TBL_VSAT_MST_DETAIL WHERE SAP_ID = P_SAPID AND CANDIDATE_ID = P_CANDIDATEID;
IF V_COUNT > 0 THEN
SELECT VSAT_DETAIL_ID INTO TBL_INSERT FROM TBL_VSAT_MST_DETAIL WHERE SAP_ID = P_SAPID AND CANDIDATE_ID = P_CANDIDATEID;
UPDATE TBL_VSAT_MST_DETAIL SET
CIRCLE = P_CIRCLE,
CONTACT_DETAILS = P_CONTACT_DETAILS,
SITE_TYPE = P_SITETYPE,
SITE_DETAILS_DIMENSION = P_SITE_PLOT_DIMENSION,
SITE_DETAILS_TECHNOLOGY = P_TECHNOLOGY
WHERE VSAT_DETAIL_ID = V_VSAT_DETAIL_ID
RETURNING VSAT_DETAIL_ID INTO TBL_INSERT;
ELSE
INSERT INTO TBL_VSAT_MST_DETAIL
(
SAP_ID,
CIRCLE,
CANDIDATE_ID,
SITE_ID,
PRIORITY,
SITE_NAME,
LATITUDE,
LONGITUDE,
CONTACT_DETAILS,
SITE_TYPE,
SITE_DETAILS_DIMENSION,
SITE_DETAILS_TECHNOLOGY
VALUES
(
P_SAPID,
P_CIRCLE,
P_CANDIDATEID,
P_SITEID,
P_PRIORITYID,
P_SITENAME,
P_LATITUDE,
P_LONGITUDE,
P_CONTACT_DETAILS,
P_SITETYPE,
P_SITE_PLOT_DIMENSION,
P_TECHNOLOGY
) RETURNING VSAT_DETAIL_ID INTO TBL_INSERT;
END IF;
IF TBL_INSERT > 0 THEN
BEGIN
SELECT COUNT(*) INTO V_PANAROMICIMG_COUNT FROM TBL_VSAT_IMAGE_DETAIL WHERE IMG_TYPE = 'Panaromic' AND IMG_ID = TBL_INSERT;
SELECT COUNT(*) INTO V_SATELLITEIMG_COUNT FROM TBL_VSAT_IMAGE_DETAIL WHERE IMG_TYPE = 'Satellite' AND IMG_ID = TBL_INSERT;
SELECT COUNT(*) INTO V_SITEPLOTIMG_COUNT FROM TBL_VSAT_IMAGE_DETAIL WHERE IMG_TYPE = 'SitePlot' AND IMG_ID = TBL_INSERT;
IF V_PANAROMICIMG_COUNT > 0 THEN
BEGIN
DELETE FROM TBL_VSAT_IMAGE_DETAIL WHERE IMG_TYPE = 'Panaromic' AND IMG_ID = TBL_INSERT;
END;
END IF;
IF V_SATELLITEIMG_COUNT > 0 THEN
BEGIN
DELETE FROM TBL_VSAT_IMAGE_DETAIL WHERE IMG_TYPE = 'Satellite' AND IMG_ID = TBL_INSERT;
END;
END IF;
IF V_SITEPLOTIMG_COUNT > 0 THEN
BEGIN
DELETE FROM TBL_VSAT_IMAGE_DETAIL WHERE IMG_TYPE = 'SitePlot' AND IMG_ID = TBL_INSERT;
END;
END IF;
FOR PMULTIFIELDS IN (SELECT REGEXP_SUBSTR(P_PANORAMIC_IMAGES,'[^,]+', 1, LEVEL) AS IMAGES FROM DUAL
CONNECT BY REGEXP_SUBSTR(P_PANORAMIC_IMAGES, '[^,]+', 1, LEVEL) IS NOT NULL
)
LOOP
INSERT INTO TBL_VSAT_IMAGE_DETAIL
(
IMG_ID,
IMG_NAME,
IMG_TYPE,
IMG_UPLOADED_DATE,
UPLOADED_BY
)
VALUES
(
TBL_INSERT,
PMULTIFIELDS.IMAGES,
'Panaromic',
SYSDATE,
P_CREATEDBY
);
END LOOP;
FOR PSATELLITEIMG IN (SELECT REGEXP_SUBSTR(P_SATELLITE_IMAGES,'[^,]+', 1, LEVEL) AS IMAGES FROM DUAL
CONNECT BY REGEXP_SUBSTR(P_SATELLITE_IMAGES, '[^,]+', 1, LEVEL) IS NOT NULL
)
LOOP
INSERT INTO TBL_VSAT_IMAGE_DETAIL
(
IMG_ID,
IMG_NAME,
IMG_TYPE,
IMG_UPLOADED_DATE,
UPLOADED_BY
)
VALUES
(
TBL_INSERT,
PSATELLITEIMG.IMAGES,
'Satellite',
SYSDATE,
P_CREATEDBY
);
END LOOP;
IF P_SITEPLOT_IMAGES IS NOT NULL THEN
BEGIN
INSERT INTO TBL_VSAT_IMAGE_DETAIL
(
IMG_ID,
IMG_NAME,
IMG_TYPE,
IMG_UPLOADED_DATE,
UPLOADED_BY
)
VALUES
(
TBL_INSERT,
P_SITEPLOT_IMAGES,
'SitePlot',
SYSDATE,
P_CREATEDBY
);
END;
END IF;
END;
END IF;
COMMIT;
EXCEPTION WHEN OTHERS THEN
ROLLBACK;
NOTE
While updating the record my TBL_INSERT returns as NULL
Expanding on what #user7294900 pointed you towards... in the declare section you have:
V_VSAT_DETAIL_ID NUMBER:=0;
then if v_count > 0 you do:
SELECT VSAT_DETAIL_ID INTO TBL_INSERT FROM TBL_VSAT_MST_DETAIL WHERE SAP_ID = P_SAPID AND CANDIDATE_ID = P_CANDIDATEID;
UPDATE TBL_VSAT_MST_DETAIL SET
CIRCLE = P_CIRCLE,
CONTACT_DETAILS = P_CONTACT_DETAILS,
SITE_TYPE = P_SITETYPE,
SITE_DETAILS_DIMENSION = P_SITE_PLOT_DIMENSION,
SITE_DETAILS_TECHNOLOGY = P_TECHNOLOGY
WHERE VSAT_DETAIL_ID = V_VSAT_DETAIL_ID
RETURNING VSAT_DETAIL_ID INTO TBL_INSERT;
The select is setting TBL_INSERT to the ID value from your table. But when you do the update your filter is using V_VSAT_DETAIL_ID, which is still set to its initial value of zero.
You probably meant to do:
SELECT VSAT_DETAIL_ID INTO V_VSAT_DETAIL_ID FROM TBL_VSAT_MST_DETAIL WHERE SAP_ID = P_SAPID AND CANDIDATE_ID = P_CANDIDATEID;
although you could still with your current select, and use that in the update too (making the returning into a bit redundant.
Be aware though that if v_count is not exactly 1, i.e. you have more than one row matching the P_SAPID and P_CANDIDATEID values, the select will get a too-many-rows exception. You won't see that because you are silently squashing any errors you get at run time.
It's usually not a good idea to commit or rollback inside a procedure anyway; it should be up to the caller to decide what to do, as this could be one of a series of statements and calls that you really want to treat as an atomic transaction. (You may be interested in savepoints.)
If you really, really want to rollback on exception within the procedure, you should at least re-raise the exception so the caller knows there was a problem:
EXCEPTION WHEN OTHERS THEN
ROLLBACK;
RAISE;
END INSERT_INTO_VSAT_MST_DATA;
but I would avoid when others if you can.
You could also combine a few steps by getting the ID at the start (again kind of assuming there is at most one matching row), and dropping the separate count and v_count variable:
SELECT MAX(VSAT_DETAIL_ID) INTO V_VSAT_DETAIL_ID
FROM TBL_VSAT_MST_DETAIL
WHERE SAP_ID = P_SAPID AND CANDIDATE_ID = P_CANDIDATEID;
IF V_VSAT_DETAIL_ID IS NOT NULL THEN
UPDATE TBL_VSAT_MST_DETAIL SET
CIRCLE = P_CIRCLE,
CONTACT_DETAILS = P_CONTACT_DETAILS,
SITE_TYPE = P_SITETYPE,
SITE_DETAILS_DIMENSION = P_SITE_PLOT_DIMENSION,
SITE_DETAILS_TECHNOLOGY = P_TECHNOLOGY
WHERE VSAT_DETAIL_ID = V_VSAT_DETAIL_ID
RETURNING VSAT_DETAIL_ID INTO TBL_INSERT;
ELSE
...
And I'm not sure why you're doing counts before your deletes later on, and it looks like all your tbl_insert references could/should be v_vast_detail_id - there doesn't seem an obvious reason to have two variables for that. Passing in a comma-delimited string that you then have to tokenize is also a bit painful - you should consider passing in a collection of values instead, if whatever calls this can manage that.
As also pointed out, you could use merge instead of the separate insert/update logic.
You don't assign value to V_VSAT_DETAIL_ID which is used in your update as a key.
You should use merge for this kind of operations