Refreshing IG after save if validations pass - oracle-apex

I have an interactive grid with some data, when users add a new row it didnt show up(found that this is because I have written a custom procedure to save and I dont return the PK).
So I set up a dynamic action, on Save[Interactive Grid] with a server side condition Type: Inline Validation Errors NOT displayed, with a true action of Refresh region.
But the condition doesent appear to work.
When adding row which passes the validations, it refreshes just fine, but when adding a row that fails validations, the validation error shows up and a popup comes up asking if I am sure I want to procede as changes were made(tries to refresh).
I have tried changing the condition to Inline Validation Errors displayed, but that doesent work. I have tried changing Event scope to Dynamic(which I dont even know what it does), but that didnt help.
I also changed the IG primary key to ROWID from the default PK from my table if that might help with the custom save procedure.
I would prefer to fix this w/o editing the save procedure as if I have to I will need to fix up a LOT of save procedures. But if I cant I am willing to fix them. But I am not sure how.
My save procedure is formated as follows:
PROCEDURE save_table (s_variable1 IN table.variable1%TYPE
, s_variable2 IN table.variable2%TYPE
, row_status IN VARCHAR2)IS
BEGIN
CASE row_status
WHEN 'C' THEN
INSERT INTO table(variable1, variable2)
VALUES (variable1_seq.nextval, s_variable2);
WHEN 'U' THEN
UPDATE table
SET variable2= s_variable2
WHERE variable1= s_variable1;
WHEN 'D' THEN
DELETE FROM table
WHERE variable1= s_variable1;
END CASE;
END save_table;
If someone could tell me the easiest way to fix this to return the PK(variable1) or ROWID so that the IG updates that one row so I dont even need the Dynamic Action.
EDIT:
Found the easiest way to do this is to change the procedure and found out how:
PROCEDURE save_table (s_variable1 IN OUT table.variable1%TYPE
, s_variable2 IN table.variable2%TYPE
, row_status IN VARCHAR2)IS
a_variable1 table.variable1%TYPE;
BEGIN
CASE row_status
WHEN 'C' THEN
a_variable1 := variable1_seq.nextval;
INSERT INTO table(variable1, variable2)
VALUES (a_variable1, s_variable2)
RETURNING a_variable1 INTO s_variable1;
Only posted the section I changed.

RETURNING INTO clause allows us to return column values for rows affected by DML statements. You can use this in your procedure to return the column value as shown below.
DECLARE
l_id t1.id%TYPE;
BEGIN
INSERT INTO t1 VALUES (t1_seq.nextval, 'FOUR')
RETURNING id INTO l_id;
COMMIT;
DBMS_OUTPUT.put_line('ID=' || l_id);
END;
For more details on Returning into see this link

Related

Conditional forward fill in dolphindb

To simplify my question, consider the following table in dolphindb:
t=table(1..5 as id, 1 NULL 3 NULL NULL as x)
I would like to forward fill nulls ONLY for the rows that I specify. For example, only for the row with id=2. I tried the following SQL query but the result was unexpected.
update t set x=ffill(x) where id=2
The table t was not updated at all. I would appreciate it if someone can point out the mistake in my code. Thanks!
The 'where' condition in SQL is always executed before the 'select' calculations. Therefore in this case you lose the information about id=1. Try this:
update t set x=iif(id==2, ffill(x), x)
This uses dolphindb function iif. Effectively it is a loop.

Dynamic where clause using page item in interactive report does not work

I simply created a interactive report based on the oracle table and set a Hidden Page Item called P1_contrain_parameter to receive the value passed from another page. The P1_contrain_parameter is used in the where clause as follow:
(Column_name = :P1_contrain_parameter)
But it does not work in this way. I tried to set the page item as Display only and found that the value has been successfully passed to the current report. I also tried to set the where clause as
(Column_name = 'actual_value')
It also works. However, it just do not what when I pass the actual value to P1_contrain_parameter to construct the dynamic where clause. Can anybody tell what might be wrong here?

Ajax call returned server error ORA-01403: no data found for APEX Interactive Grid

I am trying to save data into my table using an interactive grid with the help of custom plsql. I am running into an "ORA-01403-no data found" error while inserting data and I can't figure out why.
This is my plsql custom process which I run. Appreciate your help.
DECLARE
em_id NUMBER;
BEGIN
CASE :apex$row_status
WHEN 'C'
THEN
SELECT NVL (MAX (emergency_id), 0) + 1
INTO em_id
FROM emp_emergency_contact;
INSERT INTO emp_emergency_contact
(emergency_id, emp_id, emergency_name, emergency_relation
)
VALUES (em_id, :emp_id, :emergency_name, :emergency_relation
);
WHEN 'U'
THEN
UPDATE emp_emergency_contact
SET emergency_name = :emergency_name,
emergency_relation = :emergency_relation
WHERE emergency_id = :emergency_id;
WHEN 'D'
THEN
DELETE emp_emergency_contact
WHERE emergency_id = :emergency_id;
END CASE;
END;
So far I have not come across any documented way on how to use custom PL/SQL logic for processing submitted rows of APEX 5.1 Interactive Grid via AJAX call.
You are getting no data found error because the return is expected to be in certain json format.
The example you have provided is not too complex and can be with done using standard "Interactive Grid - Automatic Row Processing (DML)" process, which is an AJAX approach. If AJAX call is not important then you can create your own PL/SQL process with custom logic. Example of which is demonstrated in "Sample Interactive Grids" package application, check out Advanced > Custom Server Processing page in this application for more information.
I agree with Scott, you should be using a sequence or identity column for ids.
Not entirely sure. A 'select into' can raise a no_data_found exception, but yours shouldn't.
That being said, you shouldn't have max(id)+1 anywhere in your code. This is a bug. Use a sequence or identity column instead.
I have gotten this many times so the first thing I do is go look at any columns in my grid sql that are not part of the "Save", they are from a join for data only.
I just got it again and it was a heading sort column that I had as a column type of "Number". I changed it to display only and the "Save" now works.
Although, I had already set the "Source" of the column to "Query Only" which is also needed.
It is a bummer the Ajax error message doesn't at least give the column name that caused the error.
Hope this helps someone..
BillC
Add a RETURNING INTO clause after the insert. IG expects a primary key to be returned to query the inserted row.

Copy Records in Oracle Apex

I need to copy selected row values and store as a new record.
I am using Oracle Apex 4.2 and Tabular Form.
I need to use checkbox to select the rows and button copy. When i select multiple rows followed by click copy button to copy all the selected row values as new rows and save.
Can anyone Help
Copying Records Through an APEX Tabular Form Input
The idea of cloning existing records from a single table through an Oracle APEX Tabular Form works without much interference with the default design that you can set up through the APEX wizard for page region content.
Build a table with an independent primary key.
Suggested to include two auxiliary columns: COPY_REQUEST and COPIED_FROM for running copy operations. Specific form elements will map to these columns on the tabular form that will be set up.
Build an Oracle stored procedure that can read which records need to be copied. This procedure will be invoked each time the SUBMIT button is pressed.
(optional) Consider including a suppression of step (3) in the event that there is nothing to process (i.e., no records marked for copying).
The Working Table for Receiving Input: COPY_ME
TIP: You will have an easier time if you use the standard TABLE creation wizard. Designate CUSTOMER_ID as the PRIMARY_KEY and have APEX create its standard auto-incrementing functionality on top. (sequence plus trigger set up.)
Here's the sample data I used... though it doesn't matter. You can put in your own values and be able to verify what happened easily.
The Heavy Lifting: The Stored Procedure for Cloning Records in COPY_ME
This procedure works with 1 or more records at a time with a special identifier in the COPY_REQUEST table. After the task is done, the procedure cleans up and resets the request value again.
create or replace procedure proc_copy_me_request is
c_request_code CONSTANT char(1):= 'Y';
cursor copy_cursor is
SELECT cme.CUSTOMER_ID, cme.CUSTOMER_NAME, cme.CITY, cme.COUNTRY,
cme.COPY_REQUEST
FROM copy_me cme
WHERE cme.COPY_REQUEST = c_request_code
FOR UPDATE OF cme.COPY_REQUEST;
BEGIN
FOR i in copy_cursor LOOP
INSERT INTO copy_me (customer_name, city, country, copied_from)
VALUES (i.customer_name, i.city, i.country, i.customer_id);
UPDATE copy_me
SET copy_request = null
WHERE CURRENT OF copy_cursor;
END LOOP;
COMMIT;
END proc_copy_me_request;
There is also a column that can be hidden. It tracks where the record was originally copied from.
Note that the cursor is using the FOR UPDATE OF and WHERE CURRENT OF notation. This is important because the procedure is changing the records that are referenced by it.
APEX Page Setup Instructions
Set up a standard FORM type page and choose the TABULAR FORM style. Follow the set up instructions, taking care to map the correct primary key, and also to the PK sequence object created with the table in the previous steps above.
This is what your page set up will look like after these steps are completed:
EDIT The COPY_REQUEST Form Value:
Under the column attributes section, change the Display As option to "simple checkbox"
Under the list of values section, put a single value under the LOV Definition: Y (case sensitive in either way... just be consistent)
EDIT The COPIED_FROM Form Value:
Under the column attributes section, change the Display As option to "Display as Text(Saves State)". This is just to prevent users from stepping on this read-only field. You could also suppress it if it isn't important to know.
CREATE a New Process: Execute Copy Procedure
This is the bottom of the same configuration page, there are very few things to change or add:
Demonstration: Screenshot of COPY_ME Tabular Form Page in Action
The first screenshot below is before the page is tidied up and the checkbox control is put into place.
Plug in some test data and give it at try. The Page Process created in the step above conditionally invokes the stored procedure that processes all copy requests made at the same time when the SUBMIT form button is selected.
COMMENTS: If you spend enough time tinkering around with the built-in wizards in Oracle APEX, there are opportunities to learn new design patterns and process flows compatible within the tool. Adapting your approach can reduce the amount of additional work and frustration.

Django - Insert Without Returning the Id of the Saved Object

Each time the save() method is called on a Django object, Django executes two queries one INSERT and one SELECT. In my case this is usefull except for some specific places where each query is expensive. Any ideas on how to sometimes state that no object needs to be returned - no SELECT needed.
Also I'm using django-mssql to connect to, this problem doesn't seem to exist on MySQL.
EDIT : A better explanation
h = Human()
h.name='John Foo'
print h.id # Returns None, No insert has been done therefore no id is available
h.save()
print h.id # Returns the ID, an insert has taken place and also a select statement to return the id
Sometimes I don't the need the retruning ID, just insert
40ins's answer was right, but probably it might have higher costs...
When django execustes a save(), it needed to be sure if the object is a new one or an existing one. So it hits the database to check if related objext exists. If yes, it executes an UPDATE, orherwise it executes an ISERT
Check documentatin from here...
You can use force_insert or force_update ,but that might be cause serious data integrity problems, like creating a duplicate entry instead of updating the existing one...
So, if you wish to use force , you must be sure whether it will be an INSERT or an UPDATE...
Try to use save() method with force_insert or force_update attributes. With this attributes django knows about record existence and don't make additional query.
The additional select is the django-mssql backend getting the identity value from the table to determine the ID that was just inserted. If this select is slow, then something is wrong with your SQL server/configuration because it is only doing SELECT CAST(IDENT_CURRENT(*table_name*) as bigint) call.