From my APEX page I am opening a pop up page and trying to load it with data from the database. To do so, I used
Pre-Rendering After Header Process. Process type is set to PL/SQL code:
BEGIN
IF :P3_RECORD_ID IS NOT NULL THEN
select TYPE_ID, RECORD_TEXT
INTO :P3_TYPE_ID, :P3_RECORD_TEXT
from TABLE1
where RECORD_ID = :P3_RECORD_ID;
END IF;
END;
On the pop up page I have a dropdown (P3_TYPE_ID) which is filled from the LOV and a text field (P3_RECORD_TEXT).
The values show up in the session state but not in the dropdown or a text field. I can't figure out what am I doing wrong...
I also tried Automated Row Fetch but that did not load any values into fields either, just into session state
Did you consider using default value for those items? It would be a "PL/SQL Function Body" and look like this (for P3_TYPE_ID):
declare
l_type_id table1.type_id%type;
begin
select max(type_id)
into l_type_id
from table1
where record_id = :P3_RECORD_ID;
return l_type_id;
end;
I used MAX function to avoid possible NO_DATA_FOUND and TOO_MANY_ROWS errors. Handle them in EXCEPTION section, if necessary.
Similarly, populate P3_RECORD_TEXT.
Related
Question 1 :
while inserting how will you check whether the value you entered in that textbox does matched with that in the database.
My example and approach not working. error displayed is:
table, view does not allow in this context.
when button pressed[Add button]
//blockname compare //database table DRINK, column drink_id
IF (:RESERVATION_BLOCK.DRINK_ID<>DRINK.DRINK_ID) THEN
MESSAGE('IF PART');
ELSE
MESSAGE('ELSE PART');
END IF;
QUESTION 2:
Using if statement to add in database
not working error displayed is when button pressed trigger raised
unhandled exception ORA-00001.
My example not working: when button pressed [SAVE button] code works perfectly without if statement but that's not a good practice when having null
IF (:RESERVATION_BLOCK.DRINK_ID is null) THEN
MESSAGE('No Drink Ordered');
ELSIF (:RESERVATION_MENU_DRINK_BLOCK.DRINK_ID is not null) THEN
INSERT INTO RESERVATION_DRINK
VALUES(
:RESERVATION_BLOCK.RESERVATION_ID, //comes from previous tab pane block
:RESERVATION_MENU_DRINK_BLOCK.DRINK_ID,
:RESERVATION_MENU_DRINK_BLOCK.QUANTITY);
COMMIT;
MESSAGE('DRINK ORDER SAVED SUCCESSFULLY!');
END IF;
The first part of the question: you can't reference table in IF, do it before it:
DECLARE
l_cnt NUMBER;
BEGIN
SELECT COUNT (*)
INTO l_cnt
FROM drink d
WHERE d.drink_id = :reservation_block.drink_id;
IF l_cnt > 0
THEN
MESSAGE ('That ID exists');
ELSE
MESSAGE ('That ID does not exist');
END IF;
END;
As of your second question: ORA-00001 means that you tried to insert a duplicate value which is restricted by unique index (might be a primary or unique key constraint).
What to do?
fix the ID value; I don't have how you populated it into the block, but you did it wrong. Consider using a sequence so that Oracle would make sure that values are always unique
modify the constraint; maybe it has to be composite (having two or more columns, not just the ID)
probably the most stupid solution, but - it is a solution, after all: drop the unique constraint
How to generate Success Message in Apex without using custom scripts like this video
I made a form and a button, this button inserts data into a table with identity PK using PLSQL, I want to display success message with the generated ID
The button has PLSQL like this
DECLARE
V_ID INT;
BEGIN
INSERT INTO TABLE(COL) VALUES (:VALUE) returning ID into :V_ID ;
apex_application.g_print_success_message :=
'<span style="green">'||:V_ID || 'added </span>';
END;
the row is inserted into the database but Nothing is displayed
The Video is useless to me because he/she altered an existing message, this is why apex_application.g_print_success_message worked for the author of the video but I want to display a message like that in the first place, so how to display the message I just created.
create a hidden page item, let's call it P1_RETURNED_ID
button runs a process, right? That's your PL/SQL block. Change it to
insert into your_table (col) values (:P1_SOME_VALUE)
returning id into :P1_RETURNED_ID;
Put this into the "Success message" property:
Added was &P1_RETURNED_ID.
(literally, ampersand (&) followed by item name (P1_RETURNED_ID) followed by dot (.)
I am trying to create a row level trigger to delete a row if a value in the row is being made NULL. My business parameters state that if a value is being made null, then the row must be deleted. Also, I cannot use a global variable.
BEGIN
IF :NEW.EXHIBIT_ID IS NULL THEN
DELETE SHOWING
WHERE EXHIBIT_ID = :OLD.EXHIBIT_ID;
END IF;
I get the following errors:
ORA-04091: table ISA722.SHOWING is mutating, trigger/function may not see it
ORA-06512: at "ISA722.TRG_EXPAINT", line 7
ORA-04088: error during execution of trigger 'ISA722.TRG_EXPAINT'
When executing this query:
UPDATE SHOWING
SET EXHIBIT_ID = NULL
WHERE PAINT_ID = 5104
As already indicated this is a terrible idea/design. Triggers are very poor methods for enforcing business rules. These should be enforced in the application or better (IMO) by a stored procedure called by the application. In this case not only is it a bad idea, but it cannot be implemented as desired. Within a trigger Oracle does not permit accessing the table the trigger fired was fired on. That is what mutating indicates. Think of trying to debug this or resolve a problem a week later. Nevertheless this non-sense can be accomplished by creating view and processing against it instead of the table.
-- setup
create table showing (exhibit_id integer, exhibit_name varchar2(50));
create view show as select * from showing;
-- trigger on VIEW
create or replace trigger show_iiur
instead of insert or update on show
for each row
begin
merge into showing
using (select :new.exhibit_id new_eid
, :old.exhibit_id old_eid
, :new.exhibit_name new_ename
from dual
) on (exhibit_id = old_eid)
when matched then
update set exhibit_name = new_ename
delete where new_eid is null
when not matched then
insert (exhibit_id, exhibit_name)
values (:new.exhibit_id, :new.exhibit_name);
end ;
-- test data
insert into show(exhibit_id, exhibit_name)
select 1,'abc' from dual union all
select 2,'def' from dual union all
select 3,'ghi' from dual;
-- 3 rows inserted
select * from show;
--- test
update show
set exhibit_name = 'XyZ'
where exhibit_id = 3;
-- 1 row updated
-- Now for the requested action. Turn the UPDATE into a DELETE
update show
set exhibit_id = null
where exhibit_name = 'def';
-- 1 row updated
select * from show;
-- table and view are the same (expect o rows)
select * from show MINUS select * from showing
UNION ALL
select * from showing MINUS select * from show;
Again this is a bad option yet you can do. But just because you can doesn't mean you should. Or that you'll be happy with the result. Good Luck.
You have written a trigger that fires after or before a row change. This is in the middle of an execution. You cannot delete a row from the same table in that moment.
So you must write an after statement trigger instead that only fires when the whole statement has run.
create or replace trigger mytrigger
after update of exhibit_id on showing
begin
delete from showing where exhibit_id is null;
end mytrigger;
Demo: https://dbfiddle.uk/?rdbms=oracle_18&fiddle=dd5ade700d49daf14f4cdc71aed48e17
What you can do is create an extra column like is_to_be_deleted in the same table, and do this:
UPDATE SHOWING
SET EXHIBIT_ID = NULL, is_to_be_deleted = 'Y'
WHERE PAINT_ID = 5104;
You can use this parameter to implement your business logic of not showing the null details.
And later you can schedule a batch delete on that table to clean up these rows (or maybe archive it).
Benefit: you can avoid an extra unnecessary trigger on that table.
Nobody, will suggest you to use trigger to do this type of delete as it is expensive.
Can I create an AFTER TRIGGER on a table and using that table in my SELECT query without getting mutating table error?
Example to a query I want to use.
This query will update number of times a certain status name is showing up in alert life cycle:
CREATE OR REPLACE TRIGGER COUNT_STEP
AFTER INSERT
ON STEPS
FOR EACH ROW
DECLARE
V_COUNT_SETP VARCHAR (10000);
BEGIN
SELECT COUNT (STATUS_NAME)
INTO V_COUNT_SETP
FROM (SELECT A.ALERT_ID, S.STATUS_NAME
FROM ALERTS A, ALERT_STATUSES S, STEPS ST
WHERE :NEW.ALERT_INTERNAL_ID = A.ALERT_INTERNAL_ID
AND ST.ALERT_STATUS_INTERNAL_ID = S.STATUS_INTERNAL_ID
AND S.STATUS_NAME IN ('Auto Escalate'))
GROUP BY ALERT_ID;
UPDATE ALERTS A
SET A.COUNT = V_COUNT_ESC
WHERE A.ALERT_INTERNAL_ID = :NEW.ALERT_INTERNAL_ID;
END;
/
The table I'm inserting a record to is also needed for counting the number of step occurrences since it's stores the alert id and all the steps id it had.
You need to be a bit more clearer in your questions. But, from what i understood, you need to create a trigger on a table, and perform a select for that same table. That gives you a mutanting table error. To bypass that, you need to perform a compound trigger on that table. Something like this:
create or replace trigger emp_ct
for insert on employees compound trigger
v_count number; -- Add variable here
before statement is
begin
-- PERFORM YOUR SELECT AND SEND TO A VARIABLE
end before statement;
after each row is
begin
-- DO WANT YOU WANTED TO DO. USE THE VARIABLE
end after each row;
end;
basically, with a compound trigger, you can capture every trigger event. By doing that, allows to query the table you're capturing.
I am creating an overloaded PLSQL stored procedure which allows to display the names of schools, their corresponding category (elementary, etc), and neighbourhood they belong to.
The names of schools is taken from table OTTAWASCHOOLS from the field NAME. The category is taken from the table OTTAWASCHOOLS from the field CATEGORY.
In addition, the user has the choice to input a particular neighbourhood to find the above information of the schools in that neighbourhood. The name of the neighbourhood is taken from the OTTAWANEIGHBOUR table from the field NAME.
However, if the user does NOT input a specific neighbourhood, the output will display the names ALL the schools in the OTTAWASCHOOLS table with their respective neighbourhoods and categories
(I have created only one procedure at the moment).
My code is as follows
SET SERVEROUTPUT ON;
SET VERIFY OFF
CREATE OR REPLACE PACKAGE schools_package
AS
PROCEDURE find_school
(neighbourhood_name IN OTTAWANEIGHBOUR.NAME%TYPE);
END schools_package;
/
CREATE OR REPLACE PACKAGE BODY schools_package
AS
PROCEDURE find_school
(neighbourhood_name IN OTTAWANEIGHBOUR.NAME%TYPE)
IS
school_category OTTAWASCHOOLS.CATEGORY%TYPE;
school_name OTTAWASCHOOLS.NAME%TYPE;
v_neighbourhood_name OTTAWANEIGHBOUR.NAME%TYPE;
CURSOR c_schools IS
SELECT NAME, CATEGORY
FROM eluliGDM.OTTAWASCHOOLS;
r_schools c_schools%ROWTYPE;
BEGIN
FOR r_schools IN c_schools
LOOP
SELECT c1.NAME, c2.NAME, c2.CATEGORY
INTO v_neighbourhood_name, school_name, school_category
FROM eluliGDM.OTTAWANEIGHBOUR c1, eluliGDM.OTTAWASCHOOLS c2
WHERE SDO_RELATE (c2.GEOMETRY, c1.GEOMETRY, 'MASK=INSIDE+COVEREDBY QUERYTYPE=JOIN') = 'TRUE'
AND c2.NAME=r_schools.NAME;
DBMS_OUTPUT.PUT_LINE ('NEIGHBOURHOOD ' || 'CATEGORY '|| 'SCHOOL NAME ');
DBMS_OUTPUT.PUT_LINE ('------------- ' || '-------- '|| '----------- ');
DBMS_OUTPUT.PUT_LINE (v_neighbourhood_name || school_category|| school_name);
END LOOP;
CLOSE c_schools;
END find_school;
END schools_package;
-----------TESTING STORED PROCEDURE---------------
Execute schools_package.find_school();
Execute schools_package.find_school('Mer Bleue');
But when I test the procedure, I get an error :01001. 00000 - "invalid cursor" then proceeds to show me ALL neighborhoods and their corresponding schools. What is wrong with my cursor?
Remove the CLOSE c_schools; statement. The Cursor For Loop already takes care of that. See Oracle Docs:
"The cursor FOR LOOP statement implicitly declares its loop index as a record variable of the row type that a specified cursor returns, and then opens a cursor. With each iteration, the cursor FOR LOOP statement fetches a row from the result set into the record. When there are no more rows to fetch, the cursor FOR LOOP statement closes the cursor."
According to your typing, OTTAWASCHOOLS contains both columns NAME and CATEGORY, so the cursor itself appears to be validly defined.
OTOH, does schema eluliGDM own both the tables and the package? If that is not the package owner, perhaps there are privilege issues? If the schema is the same, why specify the schema in the code? If not the same, consider the use of synonyms and removing the hard-coded schema from the code.
I'm not sure why you have an input parameter; you're not using it. So, I'm not surprised you're getting all the schools; the cursor has no predicate so it's the full table, and the SELECT inside the LOOP joins wherever the NAME column is the same in both tables. Without anything to limit based on input parameter, you have no filters at all beyond the join.
HTH