Access "Page Items to Submit" values inside a trigger in oracle apex - oracle

I want to access extra page item value from a trigger which isn't in the related data table. For an example I have a table like below,
Employee
----------------------
empId | fName | lName
----------------------
1 | John | Doe
----------------------
2 | Jane | Doe
Apex form items will be like,
P500_EMPID, P500_FNAME, P500_LNAME
I have an extra page item called P500_SOMEIDSwhich is a multi select list. I want to access those selected values inside After Insert trigger of the Employee table. I tried to add this item into "Page Items to Submit". But I do not know how to access it inside that trigger. Is it possible..? and How..?

In the page process that handles your table update (that will be a process of type "Form - Automatic Row Processing (DML)", under "Settings" there is a attribute "Return Primary Key(s) after Insert". If that is set to "On", then the insert statement will return the value of the inserted row into the page item that is defined as your primary key.
Example:
Create a form on emp
Make P1_EMPNO the primary key page item
Suppose you create a new row, and that empno value is 1000. Then after the automatic row processing page process is run, the value of P1_EMPNO is set to 1000.
If you want to insert rows into another table referencing the newly created empno then you can create a page process (that executes after the row processing) of type pl/sql code like this:
BEGIN
INSERT INTO some_other_table (empno) VALUES (:P1_EMPNO);
END;
Using triggers for business functionality should be avoided whenever possible.

Instead of a database trigger, use a stored procedure which will do the same job. Pass any number of parameters you want (including the P500_SOMEIDS item).

Related

Validation checks in PL/SQL

As per my project requirement, I need to store all validation check queries in one table and validate all records of another table and update each record with its validation status.
For example, I have two tables called EMP and VALIDATIONS
Validation table has two columns as below:
------------------- --------------
Validation_desc Validation_sql
------------------ --------------
EID_IS_NULL related SQL should be here
SAL_HIGH related SQL should be here
EMPtable has normal columns like eid,ename,sal,dept,is_valid,val_desc.
I should write PL/SQL code which will fetch all validation sql's from VALIDATIONS table and check each record of EMP table and validate them. If first record got success with all validations which are available in VALIDATIONS table then EMP table IS_VALID column should be updated with 1 and Validation_desc should be null for that particular record. If second record got failed with 2 checks then that record's IS_VALID column should be updated with 0 and Validation_desc should be updated with those Validation_descwith comma separated, like wise it should check all validations for all records of EMP table.
I have tried below code to fetch all details from both the tables but not able to write logic for validations.
CREATE PROCEDURE P_VALIDATION
as
TYPE REC_TYPE IS RECORD( Validation_desc VARCHAR2(4000),
Validation_sql VARCHAR2(4000));
TYPE VAL_CHECK_TYPE IS TABLE OF REC_TYPE;
LV_VAL_CHECK VAL_CHECK_TYPE;
CURSOR CUR_FEED_DATA IS SELECT * FROM EMP;
LV_FEED_DATA EMP%ROWTYPE;
BEGIN
SELECT Validation_desc, Validation_sql
BULK COLLECT INTO LV_VAL_CHECK FROM VALIDATIONS;
OPEN CUR_FEED_DATA;
LOOP
FETCH CUR_FEED_DATA INTO LV_FEED_DATA;
EXIT WHEN CUR_FEED_DATA%NOTFOUND;
FOR I IN LV_VAL_CHECK.FIRST .. LV_VAL_CHECK.LAST LOOP
----SOME VALIDATIONS LOGIC HERE--
END LOOP;
END LOOP;
CLOSE CUR_FEED_DATA;
END;
There is no single type of validation. Validations can be is null, is not null, is true/false, returns rows/no rows etc. There are a couple of ways to tackle this
write your own assertion package with a procedure for each type of validation. In your table you'd store the type of validation and the expression to be evaluated. This is quite a bit of work.
leverage an open source testing framework like utPLSQL and modify that a bit to suit your needs. All kind of validations have already been implemented there. If you decide to go this route, note that there are major differences between version 2 and 3
First off pay attention to #KoenLostrie opening sentence: There is no single type of validation. This basically says no single process will solve the problem. But using the database's built in validations should be your first line of attack. Both of the example validation simply cease to be necessary with simple predefined constraints:
Use a constraint to define ... — a rule that
restricts the values in a database. Oracle Database lets you create
six types of constraints ...
For the table you outlined constraints can handle validations you outlined and a couple extras:
+-------------+--------+----------------------------------+-----------------------------------------------------+
| Validation | Column | Constraint Type | Description |
+-------------+--------+----------------------------------+-----------------------------------------------------+
| Eid_is_Null | eid | Primary Key | Guarantees eid is not null and is unique in table |
+-------------+--------+----------------------------------+-----------------------------------------------------+
| Sal_High | salary | Check (salary <= 50000) | Guarantees salary column is not greater than 50,000 |
+-------------+--------+----------------------------------+-----------------------------------------------------+
| Dept_OK | dept | not null | Ensures column is present |
+ +----------------------------------+-----------------------------------------------------+
| | | Foreign key to Departments table | Guarantees value exists in reference table |
+-------------+--------+----------------------------------+-----------------------------------------------------+
| Name_Ok | ename | not null | Ensures column is present |
+-------------+--------+----------------------------------+-----------------------------------------------------+
For the listed above, and any other constraint added, you do not need a query to validate - the database manager simply will not allow an invalid row to exist. Of course now your code needs to handle the resulting exceptions.
Unfortunately constraints cannot handle every validation so you will still need validation routines to record those. However, you should not create a comma separated list (not only do they violate 1st normal form they are always more trouble than they are worth - how do you update the list when the error is resolved?) Instead create a new table - emp_violations as:
create table emp_violations (
emp_vio_id integer generated always as identity
, emp_id integer -- or type of emp_id
, vol_id integer -- or type of vio_id (the pk of violations table)
, date_created date
, date_resolved date
, constraint emp_violations_pk
primary key (emp_violation_id)
, constraint emp_violations_2_emp_fk
foreign key (emp_id)
references emp(mp_id)
, constraint emp_violations_2_violations_fk
foreign key (vio_id)
references violations(vio_id)
);
With this it is easy to see what non-constraint violations have, or currently exist, and when they were resolved. Also remove the columns Validation_desc (no longer needed) and is_valid (derivable from unresolved emp_violations requiring no additional column maintenance).
If you absolutely must get is_valid and a comma separated list of violations then create a view with the LISTAGG function.

Disparity between populated id column and returned value from hibernate after save

A sequence is used to generate id for a customer table and then using trigger to populate the id column as a varchar value.
The trigger is
CREATE OR REPLACE TRIGGER USER_ID_TRIGGER
before insert on CUSTOMER
REFERENCING NEW AS New OLD AS Old
for each row
begin
-- :new.user_id := 'CUST' || :new.user_id ;
select 'CUST' || SEQ_CUSTOMER_ID.nextval into :new.user_id from dual;
end USER_ID_TRIGGER;
So, each insert in the column is like 'CUST1', 'CUST3', etc.
The trigger can't be changed.
I am using hibernate save(customer) method to save customer objects in the db. Problem is the return id value I am getting is (as expected) different from the one that is ultimately saved in the table.
For example, if the id populated in the column is 'CUST19', the hibernate code returns 18.
My question is, if the code returns a value of 210, will it be safe for me to assume that the populated value is CUST211?

Statement level Trigger or Row Level Trigger

Which trigger to use - Statement or Row level?
If I use row level trigger , how to restrict it to insert data in tracking table only once for a group of entries in VALUES table
Database Schema -
ITEM_VERSIONS TABLE - Item_id,Version id,start_version_id,end_version_id
ITEM_VALUES_TABLE- Value Id, Value, Item_id, Start_version , End Version
Each time an item is created :
ITEM_VERSIONS TABLE - This table stores all the information of Item Versions.
For 1 item version, it has 1 row.
ITEM_VALUES_TABLE - This has all the values info .
So for 1 item , this table has 15-20 rows for each value attribute. Lets say Item_date , color etc
I want to create a trigger on ITEM_VALUES_TABLE and insert the version id in the tracking table.
To get version id, I have to use ITEM_VERSIONS TABLE to get the version id of the item and then update in the tracking table

How to create and use a multi-select list in APEX ORACLE?

I have a table called Employees with Employee_id and Employee_Name columns. Now i want to create a page with Checkbox in-front of every Employee Name, select the ones that are needed, store them into a temporary table and use them for further operations. The problem i am facing is to how to create that multi select list and store the select values in thee table. Is there an Item for multi select? If not, how should i do it?
There's the Shuttle item. On the left side, you'd display list of all employees. Item buttons allow you to move all (or only some of them) to the right side of the item. Once you submit the page, list of employee IDs is stored into a table column in a form of colon-separated values, for example
6547:8879:5587:9987
This is a simple way of doing that. However, once you have to actually do something with those values, you have to split them to rows. Not a problem, though. Here's a query:
SQL> with emps (shuttle_item) as
2 (select '6547:8879:5587:9987' from dual)
3 select regexp_substr(shuttle_item, '[^:]+', 1, level) one_item
4 from emps
5 connect by level <= regexp_count(shuttle_item, ':') + 1;
ONE_ITEM
---------------------------------------------------------------------
6547
8879
5587
9987
SQL>
Or, you could create a tabular form which also displays all employees and has checkboxes at the beginning of every line. You'd then create a process which - in a loop - stores selected values into a temporary table you mentioned. For example:
-- F01 = row selector. If you check 1st and 3rd row, f01.count = 2 (2 rows checked)
-- f01(1) = 1 (row #1), f01(2) = 3 (row #3)
-- F02 = EMP_ID. f02(1) = EMP_ID that belongs to employee in 1st row,
-- f02(3) = EMP_ID that belongs to emplyee in 3rd row
declare
l_id number;
begin
for j in 1 .. apex_application.g_f01.count
loop
l_id := apex_application.g_f02(apex_application.g_f01(j));
insert into temp_table (emp_id) values (l_id);
end loop;
end;
There is an option for creating multi select list in oracle apex 5.1.
Create a pageItem of type: 'select list'.
Make the 'Allow multi
selection' to 'Yes'.
Write the SQL query for your select list under
the 'List of Values' attribute.
Then the select list will be
displayed based on our query.
Query format is:
select [displayValue],
[returnValue]
from ...
where ...
order by ...
Now once you select multiple value from select list(using ctrl+click), these are stored as ':' separated values in the select list page item.
I've created a video some times ago that covers your problem. It's a step by step tutorial how to create checkboxes and process them.
Video is available here:
https://www.youtube.com/watch?v=T-LXRMWQbPk
Regards
If the list is too big, I recommend to use the Popup LOV item with the Multiple Values switch activated instead the Select list or the Shuttle, because it has an internal search field for the objects list, doing way easier for the user to find the target values. Also, just as the Select List or Shuttle item, you can set a Separator character for the selected fields.

Oracle Apex 5.1 Custom Master Details

Oracle Apex 5.1 Custom Master Details Problem
I have created a page with two region,
1. dept (some text field, deptno, dname)
2. emp (interactive grid , ename, deptno)
And one submit Button
Flow : User input manually department name on 'dname' text field
And add some employees row on grid and finally when user click on submit button then first create a department with deptno (auto increment)
And then insert grid row with deptno which created first region.
That means every deptno has some corresponding employee and both task will create same times.
(after click on submit button)
If possible and you understand about this please give me a solution.
On your page create a hidden item that will have your new department id, named P1_depno in this example.
When you have created the Interactive Grid with the Attributes > Edit > Enabled set to Yes an Interactive Grid - Automatic Row Processing (DML) process (most probably named - Save Interactive Grid Data) should have been added to your page (if you don't have it simply create a new process with the above type).
Before this process create a new PL/SQL process (named Insert Department in my example) that will insert the department using this code:
declare
v_depno number;
begin
select deptno_sequence.nextval into :P1_depno from dual; --get the depno from your sequence
insert into dept (deptno, dname)-- insert the new department
values (:P1_depno,:P1_dname);
end;
Very important this process must run before the Save Interactive Grid Data process.
Now edit the Save Interactive Grid Data process and at Target Type select PL/SQL Code and add the following code:
begin
--insert the employees
case :APEX$ROW_STATUS
when 'C' then -- C for Create but you also can check for U (Update) and D (Delete)
insert into emp ( empno, ename, deptno )
values ( :EMPNO, :ENAME, :P1_depno )
returning rowid into :ROWID;
end case;
end;

Resources