I am trying to make procedure that count total slab # of from each pallet from prod_result table and insert or update that count to qty column in plt_result table that has same pallet #(plt_no)
I've tried insert, update both but doesn't work.
create or replace PROCEDURE update_qty
is
v_plt_no nvarchar2(20);
v_qty number;
cursor q1 is
select count(slab_no)
into v_qty
from prod_result
where plt_no = v_plt_no;
begin
if v_qty > 0 then
update plt_result
set qty = 'v_qty'
where plt_no = v_plt_no;
end if;
end;
What am I doing wrong here? Help please.
I'm not sure which version you're looking for - is it the one that loops through all PLT_NOs in a table, or the one that should accept PLT_NO as a parameter. Here are both options, see whether any of them helps.
The first one uses cursor FOR loop; it is easier to maintain as Oracle does most of the dirty job for you (opening the cursor, fetching, exiting the loop, closing the cursor).
create or replace procedure update_qty
is
begin
for cur_r in (select plt_no, count(slab_no) v_qty
from prod_result
group by plt_no
)
loop
if cur_r.v_qty > 0 then
update plt_result r set
r.qty = cur_r.v_qty
where r.plt_no = cur_r.plt_no;
end if;
end loop;
end;
The second one accepts PLT_NO as a parameter:
create or replace procedure update_qty
(par_plt_no in prod_result.plt_no%type)
is
v_qty number;
begin
select count(p.slab_no)
into v_qty
from prod_result p
where p.plt_no = par_plt_no;
if v_qty > 0 then
update plt_result r set
r.qty = v_qty
where r.plt_no = par_plt_no;
end if;
end;
Something like the following, where you actually open and fetch from the cursor. You'll have to assign a value to v_plt_no for the cursor to fetch anything.
create or replace PROCEDURE update_qty
is
v_plt_no nvarchar2(20);
v_qty number;
cursor q1 is
select count(slab_no)
into v_qty
from prod_result
where plt_no = v_plt_no;
begin
OPEN q1;
FETCH q1 INTO v_qty;
CLOSE q1;
if v_qty > 0 then
update plt_result
set qty = 'v_qty'
where plt_no = v_plt_no;
end if;
end;
Related
I am stuck in infinite loop while using a cursor to update a record. Here is the code... Any suggestions of what should i do?
CREATE OR REPLACE PROCEDURE SHADI.filling_conditional
as
cursor filling_cursor is select * from deposits_table for update;
begin
for i in filling_cursor
loop
update deposits_table
set conditional_flag = case
when i.deposit_amount > 1000 and i.currency_code = 'JOD'
and (select customer_info.sex
from customer_info
where customer_info.customer_number = i.customer_number) = 1
then 1
else 0
end;
end loop;
end filling_conditional;
/
Please try with below procedure code:
CREATE OR REPLACE PROCEDURE SHADI.filling_conditional
as
c_deposit_amount deposits_table.deposit_amount%type;
c_currency_code deposits_table.currency_code%type;
c_customer_number deposits_table.customer_number%type;
cursor filling_cursor is select deposit_amount, currency_code, customer_number from deposits_table for update;
BEGIN
OPEN filling_cursor;
LOOP
FETCH filling_cursor into c_deposit_amount, c_currency_code, c_customer_number;
EXIT WHEN filling_cursor%notfound;
update deposits_table
set conditional_flag = case
when c_deposit_amount > 1000 and c_currency_code = 'JOD'
and (select customer_info.sex
from customer_info
where customer_info.customer_number = c_customer_number) = 1
then 1
else 0
end;
END LOOP;
CLOSE filling_cursor;
END filling_conditional;
/
I want to create trigger but I don't know how to do that. Below is the sample:
CREATE OR REPLACE TRIGGER checkDuration
after UPDATE on comm_shipping
FOR EACH ROW
DECLARE
quantity NUMBER;
BEGIN
SELECT * FROM comm_orders c
WHERE C.ORDER_ID = :new.order_id
AND c.quantity = 1;
IF quantity=NULL THEN
RAISE_APPLICATION_ERROR('no more items');
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
NULL;
END;
Try the following ( I suppose your DBMS is Oracle or DB2 because of RAISE_APPLICATION_ERROR ):
CREATE OR REPLACE TRIGGER checkDuration
AFTER UPDATE ON comm_shipping
FOR EACH ROW
DECLARE
quantity NUMBER;
BEGIN
SELECT c.quantity
INTO quantity -- this part is missing
FROM comm_orders c
WHERE c.order_id = :new.order_id;
IF quantity is NULL THEN
RAISE_APPLICATION_ERROR(-20001,'no more items'); -- you need a code
-- between -20000 and -20999
END IF;
EXCEPTION WHEN NO_DATA_FOUND THEN NULL;
END;
I am trying to write trigger which will control if a record is already in table or not. If is the record already in table (compare for example by name), so current record set valid='False' and insert new. Is there any way?
This is my idea, but it doesn't work.
create or replace TRIGGER
Check_r
before insert on t$customer
FOR each ROW
declare
v_dup number;
v_com number;
v_id number;
v_id_new number;
begin
v_date:=SYSDATE;
select count(id) INTO v_dup from t$customer where surname=:NEW.surname ;
select count(id) INTO v_com from t$customer where firstname =:NEW.firstname and
address=:NEW.address;
select id into v_id from t$customer where surname=:NEW.surname;
if v_dup > 0 and v_com=0 then
v_id_new:= m$_GET_ID; -- get id
update t$customer set valid = 'False' where id = v_id;
insert into t$customer ( id, surname ,firstname, valid, address ) values (v_id_new,:NEW.surname ,:NEW.firstname, :NEW.valid, :NEW.address);
end if;
if v_dup = 0 then
v_id_new:= m$_GET_ID; -- get id
insert into t$customer ( id, surname ,firstname, valid , address) values (v_id_new,:NEW.surname ,:NEW.firstname, :NEW.valid, :NEW.address);
end if;
end;
You can use a compound trigger, for example:
CREATE OR REPLACE TRIGGER Check_r
FOR INSERT ON t$customer
COMPOUND TRIGGER
TYPE customerRecordType IS RECORD(
surname t$customer.surname%TYPE,
firstname t$customer.firstname%TYPE,
address t$customer.address%TYPE,
ID nubmer);
TYPE customerTableType IS TABLE OF customerRecordType;
customerTable customerTableType := customerTableType();
n NUMBER;
BEFORE STATEMENT IS
BEGIN
customerTable.DELETE; -- not requried, just for better understanding
END STATEMENT;
BEFORE EACH ROW IS
BEGIN
customerTable.EXTEND;
customerTable(customerTable.LAST).surname := :NEW.surname;
customerTable(customerTable.LAST).firstname := :NEW.firstname;
customerTable(customerTable.LAST).address := :NEW.address;
customerTable(customerTable.LAST).ID := m$_GET_ID;
:NEW.ID := customerTable(customerTable.LAST).ID;
END BEFORE EACH ROW;
AFTER STATEMENT IS
BEGIN
FOR i IN customerTable.FIRST..customerTable.LAST LOOP
SELECT COUNT(*) INTO n
FROM t$customer
WHERE surname = customerTable(i).surname;
IF n > 1 THEN
UPDATE t$customer
SET valid = 'False'
WHERE surname = customerTable(i).surname;
END IF;
SELECT COUNT(*) INTO n
FROM t$customer
WHERE firstname = customerTable(i).firstname
AND address = customerTable(i).address;
IF n > 1 THEN
UPDATE t$customer
SET valid = 'False'
WHERE firstname = customerTable(i).firstname
AND address = customerTable(i).address
END IF;
END LOOP;
END AFTER STATEMENT;
END;
/
Please note, this solution is ugly and poor in terms of performance!
But it should give you an impression how it works.
In general you should put all this into a PL/SQL Procedure instead of a trigger.
First, this is trigger for insert. you don't need to write insert statement.
Second, you need to update old record. Just update it with your where clause.
CREATE OR REPLACE TRIGGER Check_r
before insert on t$customer
FOR each ROW
BEGIN
UPDATE t$customer set valid = 'False'
WHERE surname = :NEW.surname
AND firstname =:NEW.firstname;
:NEW.id := m$_GET_ID;
END;
Here is my trigger.Following error.
45 /
SP2-0552: Bind variable "OLD" not declared.
I am unable to find the error .I have tried several times but failed.I have declared every variable but the error is showing.Someone please help me .
drop trigger DELETE_Single_food
CREATE OR REPLACE TRIGGER DELETE_Single_food
BEFORE DELETE ON SingleFoodOrder
FOR EACH ROW
declare
f_price number;
old_bill number;
f_quantity number;
p_bill number;
foodID number;
orderID number;
order_date Date;
s_date Date;
f_date Date;
f_dis number;
a number;
b number;
c number;
BEGIN
IF :old.H_delivery_ID is not NULL then
foodID := :old.Fooditem_ID;
orderID := :old.H_delivery_ID;
f_quantity := :old.Quantity;
select bill into old_bill from HomeDelivery where H_delivery_ID =orderID ;
select price into f_price from Food_Item where Fooditem_ID = foodID;
select discount_percentage into f_dis from Food_Item where Fooditem_ID = foodID;
select start_date into s_date from Food_Item where Fooditem_ID = foodID;
select deadline into f_date from Food_Item where Fooditem_ID = foodID;
select H_delivery_request into order_date from HomeDelivery where H_delivery_ID =orderID;
if f_dis is not NULL then
if (order_date >= s_date and order_date<=f_date) then
a := f_dis/100;
b := f_price*a ;
c := f_price-b;
p_bill := old_bill-( c*f_quantity);
update HomeDelivery set bill = p_bill where H_delivery_ID = orderID;
else
p_bill := old_bill-(f_price*f_quantity);
update HomeDelivery set bill = p_bill where H_delivery_ID = orderID;
end if;
else
p_bill := old_bill-(f_price*f_quantity);
update HomeDelivery set bill = p_bill where H_delivery_ID = orderID;
end if;
END;
/
The problem is not in your variables declarations. I think you're not closing your main IF statement:
IF :old.H_delivery_ID is not NULL then
I don't see the END IF for that one. Add END IF; before the END;
If this does not work, you will need to do some debugging. Try just to leave only that statement in the begin block.
CREATE OR REPLACE TRIGGER DELETE_Single_food
BEFORE DELETE ON SingleFoodOrder
FOR EACH ROW
BEGIN
IF :old.H_delivery_ID is not NULL then
null;
END IF;
END;
/
See if that compiles. Then add the rest of the code to see where it breaks.
Hope this helps!
I am running the following SP but getting the error c1.pyid is invalid identifier. I am trying to use two different query results from one cursor. If there is any other way of using IF-else clause in a cursor, i am open to that too.
CREATE OR REPLACE
PROCEDURE FIX_DOCUMENT_RECORDS ( i_flag in varchar)
AS
Op_ID VARCHAR(8);
Op_Name VARCHAR(32);
skill VARCHAR(32);
temp_count VARCHAR(8);
temp_status VARCHAR(8):='Submitted';
QRYSTR VARCHAR2(400);
TYPE REF_CUR IS REF CURSOR;
c1 REF_CUR;
BEGIN
IF (i_flag='1') THEN
QRYSTR:='SELECT *
FROM dims_doc_master
WHERE concat_prod_id IS NULL
OR documenttypeid IS NULL
AND (pystatuswork = temp_status);';
ELSE
QRYSTR:='SELECT *
FROM dims_doc_master
WHERE (documentimageid IS NULL
AND p8id IS NULL)
AND (pystatuswork = temp_status);';
END IF;
open c1 FOR QRYSTR;
LOOP
BEGIN
DBMS_OUTPUT.PUT_LINE('loop begin');
UPDATE DIMS_DOC_MASTER
SET pystatuswork ='Cancelled',
documentstatus ='Cancelled',
cancellationdate='31-JAN-14',
cancelledbysid = c1.pxcreateoperator,
cancelreason ='Cancelled due to corruption.'
WHERE pyid =c1.pyid;
DBMS_OUTPUT.PUT_LINE('After updation'||c1.pyid );
--Begin PC_DOCUMENT UPDATION
UPDATE PC_DOCUMENT
SET pystatuswork ='Cancelled',
cancellationdate='31-JAN-14'
WHERE pyid =c1.pyid;
--Begin insert into History
--Select Operator name and ID
SELECT skill
INTO skill
FROM operator_map_skill
WHERE pyuseridentifier=c1.pxcreateoperator
AND rownum =1;
INSERT
INTO DIMS_DOC_HIST
(
DIMS_DOC_ID,
DOC_CHG_USR,
DOC_CHG_DT,
DOC_NEW_STS,
DOC_CHG_CMNT,
CRE_TS,
ROLE,
RSN_DESC,
TARGETROLE,
DOC_CHG_USR_ID,
DOC_ASG_USR_ID,
DOC_ASG_USR,
PREVSTATUS,
PREVSTATUSDT,
ASSIGNEDTODT,
TODISPLAY,
ACTIVITY_NAME
)
VALUES
(
c1.pyid,
'DIMS',
systimestamp,
'Cancelled',
'Cancelled due to corruption',
'31-JAN-14',
skill,
NULL,
skill,
c1.pxcreateoperator,
c1.pxcreateoperator,
c1.pxcreateopname,
'Submitted',
NULL,
systimestamp,
'Y',
'Updation through Script'
);
dbms_output.put_line
(
'Document ID= '||c1.pyid
)
;
SELECT COUNT(*)
INTO temp_count
FROM PC_ASSIGN_WORKBASKET
WHERE pxrefobjectinsname=c1.pyid;
IF(temp_count IS NOT NULL) THEN
DELETE FROM PC_ASSIGN_WORKBASKET WHERE pxrefobjectinsname=c1.pyid;
ELSE
DELETE FROM PC_ASSIGN_WORKLIST WHERE pxrefobjectinsname=c1.pyid;
END IF;
COMMIT;
END;
END LOOP;
CLOSE c1;
END;
You seem confusing cursor and fetched row.
In your current procedure: you open a cursor, do a loop (which looks to be endless since there is no EXIT statement), and after the loop you close the cursor (but it looks it will never happen)
To fetch results from a cursor, do the following:
CREATE OR REPLACE PROCEDURE ...
...
c1 REF_CUR;
ddm_record dims_doc_master%rowtype;
BEGIN
...
OPEN c1;
LOOP
FETCH c1 INTO ddm_record;
EXIT WHEN c1%NOTFOUND;
...
DBMS_OUTPUT.PUT_LINE('Document ID= ' || ddm_record.pyid); -- not c1.pyid
END LOOP;
CLOSE c1;
END;
/
Inspired from examples here: http://plsql-tutorial.com/plsql-explicit-cursors.htm
Try embedding the flag in your where clause:
open c1 FOR
SELECT *
FROM dims_doc_master
WHERE (i_flag='1' AND
(concat_prod_id IS NULL
OR documenttypeid IS NULL
AND (pystatuswork = temp_status))
OR (i_flag<>'1' AND
(documentimageid IS NULL
AND p8id IS NULL)
AND (pystatuswork = temp_status));
The logic can probably be simplified but logically that would work.