Dynamically Changing Value in APEX Based on Select List Selection - sql

I currently have a select list with the values: 1, 2, 3, 4 & 5. These correspond to a column in table "DVD" called "DVDID", and these are the only values in this column in the table.
In the table "DVDCOPY" records exist containing the all DVDIDs (1,2,3,4,5) with a different DVDCOPYID.
E.g. a record from the DVDCOPY table is:
DVDCOPYID DVDID DISCCONDID
1 1 1
My question is, how can I make it so that once a DVDID is selected from the select list, the DVDCOPYID changes dynamically based on this selection? E.g. once 1 is selected in the DVDID select list, the value for DVDCOPYID also changes to 1 automatically.
My form currently looks like this, if this helps:
APEX Form

You have to use dynamic actions and PL/SQL. Create a hidden form element which allows for element changes (no session protection enabled). Create a new dynamic action in your form guiding to the select list and using the onchange event. Your dynamic action contains two steps: first set the hidden form element to the value of your select list. Second: execute a PL/SQL statement (UPDATE DVDCOPYID SET ... = :NEW_HIDDEN_ELEMENT WHERE ID = ...).

Related

INSERT INTO table from form with checkboxes

I would like to insert multiple entries into a table using a single form.
Desired outcome:
DESTINATION_TABLE
DATE | PLACE | THEME | PARTICIPANT
dd.mm.yyyy A X 1
dd.mm.yyyy A X 2
dd.mm.yyyy B Y 3
PLACE and PARTICIPANT are to be selected from values contained in other tables, while DATE and THEME are entered using text boxes. Only one value is to be inserted into the table at a time for DATE, PLACE and THEME, but I would like to be able to insert multiple PARTICIPANT, with a new row for each PARTICIPANT selected.
Adding new entries for DATE, PLACE and THEME via a form works (using CurrentDb.Execute "INSERT INTO...).
How can I create a form that would let me select PARTICIPANT from a subform (ideally with checkboxes) filtered from the value in PLACE, and add an entry in DESTINATION_TABLE for each PARTICIPANT selected ?
One simple way of doing it, with your current setup is to:
add a Yes/No field to your participants table, default to No. We'll call this field Selected
Bind your subform to the participants table, the user will be able to check each participant from this view(using the Selected field).
From which ever event you're using to save you data(e.g. Button Click), create a recordset(rs) based on the selected participants from the participants table(SELECT * FROM PARTICIPANT WHERE Selected = True. Loop through each record in the recordset(rs) and execute your code CurrentDb.Execute "INSERT INTO...), taking the value of the participant(rs("Participant")) from the recordset.
Once the loop is finished, update the participants table setting the Selected field to No. CurrentDb.Execute "UPDATE PARTICIPANT SET Selected = False WHERE Selected = True"
Refresh/Requery your sub form data if needed
Substitute above object names with yours.

Unable to do update table from Apex 5 button Error mentions Cannot Insert NULL

Hi People of the Palace
I am not having luck here and tried a lot of things and seems as if I am not able to get the value from the field which needs to update.
There are 2 fields within Apex 5 which I want to update if something if the value is changed from default. :QUANTITY which is a text field inside of a Tabular form and :DISC which is also a text field in the same row.
There can be single or multiple rows to that needs to be updated and this is usually where you set the option "updated rows and columns only"
The table SALES_TEMP does has columns ID, NAME, QUANTITY_TO_SELL, DISCOUNT.
The PL/SQL code that is assigned in the process to do this update is as follows.
BEGIN
update SALES_TEMP
set QUANTITY_TO_SELL=:QUANTITY, DISCOUNT=:DISC;
end;
When I try and update the fields, it will return with
Cannot insert NULL into QUANTITY_TO_SELL
and similar with the DISCOUNT field.
Now I know there is nothing wrong with the query because if I do this:
BEGIN
update SALES_TEMP
set QUANTITY_TO_SELL='2', DISCOUNT='5';
end;
It does in fact update the table, but it will then do this update to all rows in the table because I have no where clause.
I have had a look through the different options and cannot seem to find why it does not select the data from the fields. My main issue is, I have an exact same query running doing an insert which works.
Also from Apex's Sql Command line option if I run.
update SALES_TEMP
set QUANTITY_TO_SELL=:QUANTITY, DISCOUNT=:DISC;
I get a popup requesting values for :QUANTITY and :DISC and it then updates the columns so something tells me that this is not getting the values from these text fields.
The SQL command to add to populate the fields are
select ID, NAME, QUANTITY_TO_SELL as QUANTITY, DISCOUNT as DISC from SALES_TEMP;
Obviously each gets assigned as :ID, :NAME :QUANTITY and :DISC in apex.
Seeing as you are using Tabular form I suggest you ensure that the following is set.
On the procedure (in processing), Ensure you have the Tabular form selected.
Ensure the Condition "When button is pressed" is set to use the button you want to assign this process to.
in Oracle update clause should ALWAYS have where clause, because oracle will update all data in the table without the WHERE clause.
The cannot insert null error occurs when you are trying to insert in one of the table attributes NULL, where parameter set to NOT NULL, so in your case try to use NVL function, to avoid this issue, I ques that the NAME atribute should not be null.
try to modify your code like this:
update SALES_TEMP
set QUANTITY_TO_SELL = :QUANTITY,
DISCOUNT = :DISC,
NAME = nvl(:NAME,'empty')
where ID = :ID;
in this case it will update only one column.
The Oracle/PLSQL NVL function lets you substitute a value when a null value is encountered.

Oracle SQL: how to enforce only one value may be 'checked'?

So I have a table in a database which contains the column "SELECTED". The values in this column can only be "CHECKED" or "UNCHECKED". I would like to enforce "CHECKED" can only be used once (like a radiobutton) through a PL/SQL trigger, though I cannot think of how to do this.
First, the idea (in case it didn't become clear):
Initial table "dummy":
ID | SELECTED
--------------
1 | 'UNCHECKED'
2 | 'CHECKED'
3 | 'UNCHECKED'
Then, I execute this query:
UPDATE dummy
SET SELECTED = 'CHECKED'
WHERE ID = 3;
Through a PL/SQL trigger, I'd like to have my table "dummy" to look like this after the execution:
ID | SELECTED
--------------
1 | 'UNCHECKED'
2 | 'UNCHECKED'
3 | 'CHECKED'
I hope you get the idea. I myself have tried to solve this, without success. I came up with the following code:
CREATE OR REPLACE TRIGGER DUMMY_ONE_CHECKED
AFTER INSERT OR UPDATE ON DUMMY
FOR EACH ROW
DECLARE
v_checked_is_present DUMMY.SELECTED%TYPE;
BEGIN
SELECT SELECTED
INTO v_checked_is_present
FROM DUMMY
WHERE SELECTED = 'CHECKED';
IF v_checked_is_present IS NOT NULL THEN
UPDATE DUMMY
SET SELECTED = 'UNCHECKED'
WHERE SELECTED = 'CHECKED';
UPDATE DUMMY
SET SELECTED = 'CHECKED'
WHERE ID = :NEW.ID;
END IF;
END;
However, I get the errors ORA-04091, ORA-06512 and ORA-04088 with the following message:
*Cause: A trigger (or a user defined plsql function that is referenced in
this statement) attempted to look at (or modify) a table that was
in the middle of being modified by the statement which fired it.
*Action: Rewrite the trigger (or function) so it does not read that table.
Clearly, this is not the right solution. I wonder how I could accomplish what I would like to do (if possible at all)?
Thank you in advance!
I would not design it that way. The database should enforce the rules, not automatically attempt to fix violations of them.
So, I'd enforce that only one row can be CHECKED at a time, like this:
CREATE UNIQUE INDEX dummy_enforce_only_one ON dummy ( NULLIF(selected,'UNCHECKED') );
Then, I'd make it the responsibility of calling code to deselect other rows before selecting a new one (rather than trying to have a trigger do it).
I know that doesn't answer the text of your question, but it does answer the title of your question: "how to enforce only one value..."
I'm not sure a trigger is the best approach to this problem. The trigger needs to update all the records for every update -- even worse, the rows are in the same table leading to the dreaded mutating table error.
How about a different table structure altogether? The idea is just to keep track of the last time something was "checked" and then use the maximum timestamp:
create table t_dummy (
id int,
checkedtime timestamp(6)
);
create view dummy as
select t_dummy.id,
(case when checkedtime = maxct then 'CHECKED' else 'UNCHECKED') as selected
from t_dummy cross join
(select max(checktime) as maxct from t_dummy) x;
This should be simpler to implement than a trigger.
One way to implement this is to use a COMPOUND TRIGGER. A compound trigger is one which has code which fires at each of the possible triggering points (BEFORE STATEMENT, BEFORE ROW, AFTER ROW, and AFTER STATEMENT). Let's look at how to handle your requirement:
CREATE OR REPLACE TRIGGER DUMMY_CHECKED_TRG
FOR INSERT OR UPDATE ON DUMMY
COMPOUND TRIGGER
TYPE NUMBER_TABLE IS TABLE OF NUMBER;
tblDUMMY_IDS NUMBER_TABLE;
BEFORE STATEMENT IS
BEGIN
tblDUMMY_IDS := NUMBER_TABLE();
END BEFORE STATEMENT;
AFTER STATEMENT IS
BEGIN
IF tblDUMMY_IDS.COUNT > 0 THEN
UPDATE DUMMY d
SET d.SELECTED = 'UNCHECKED'
WHERE d.ID <> tblDUMMY_IDS(tblDUMMY_IDS.LAST) AND
d.SELECTED = 'CHECKED';
END IF;
END AFTER STATEMENT;
AFTER EACH ROW IS
BEGIN
-- If the new value of `SELECTED` on this row is 'CHECKED'
-- save the ID of the row in tblDUMMY_IDS
IF :NEW.SELECTED = 'CHECKED' THEN
tblDUMMY_IDS.EXTEND;
tblDUMMY_IDS(tblDUMMY_IDS.LAST) := :NEW.ID;
END IF;
END AFTER EACH ROW;
END TABLE1_NUM_TRG;
In the BEFORE STATEMENT portion of the trigger we just allocate a table (variable length collection object) to hold ID values. This portion of the trigger is executed once, before any rows have been processed by the trigger.
In the AFTER EACH ROW section of the trigger we look at the SELECTED field of the row, and if it's 'CHECKED' we save its ID value in the table we allocated earlier.
The AFTER STATEMENT section of the trigger is where the real work gets done - and it's only a single SQL statement. The reason we defer the real work of the trigger until the AFTER STATEMENT section is because code which executes here will not raise the dreaded "MUTATING TABLE" exception. What we do is we take the last ID value which we found was associated with a row which had SELECTED = 'CHECKED'. This is the row which we want to remain CHECKED - every other row in the table should be UNCHECKED. So we execute an UPDATE statement, saying in effect "set SELECTED to 'UNCHECKED' on every row in the table whose ID is not the one we've got, and whose current value of SELECTED is CHECKED". Normally this will only update one row - but it will handle the case where in a single SQL statement sets a bunch of rows to CHECKED.
I believe compound triggers became available in 10g, so if you're on that version of Oracle or later you should be good.
Hope this helps.
Best of luck.
As I understand, you want to have only one row in the whole table, which could contain CHECKED value. But your way will not work.
I've just invented a new way how to do this. Maybe, it is a bit complicated way. Change your selected column type to number, and fill it with consequent numbers (for example, with sequence). Then consider column with maximal value as "selected". This gives you a lot of advantages: to change selected row you just need to take next value from a sequence and put it in desired row (you don't need to update all rows), you need only one query for that, and you never meet mutation problem. Disadvantages - quite hard to get selected row and impossible (hard) to "deselect all".
Alternative approach using table with one row only (enforced with PK). The `BUTTON_ID contains the ID of the selected button (1-3 or NULL if all buttons are un-checkedd). The button per row result is presented in a view.
create table button
(
id number primary key check (ID in (1)),
button_id number check (button_id in (1,2,3))
);
create view v_button as
with r3 as (select rownum button_id from dual connect by level <= 3)
select
case when button.button_id = r3.button_id then 'SELECTED' else 'UNSELECTED' end as button_code
from r3 cross join button
;
Initialize with
insert into button values(1,1);
gives
select * from v_button;
BUTTON_CODE
-----------
SELECTED
UNSELECTED
UNSELECTED
Switch simple with an update statement:
update button set button_id = 3;
gives
BUTTON_CODE
-----------
UNSELECTED
UNSELECTED
SELECTED
To de-select all simple set to NULL
update button set button_id = NULL;
BUTTON_CODE
-----------
UNSELECTED
UNSELECTED
UNSELECTED
Would be easier if you knew what needed to be unchecked. But if you can't, then unckeck everything.
UPDATE dummy
SET SELECTED = 'UNCHECKED';
Then check the one that you know should be checked.
UPDATE dummy
SET SELECTED = 'CHECKED'
WHERE ID = 3;
Why not use a boolean for this?
--EDIT-- (boolean example)
UPDATE dummy
SET SELECTED = 0;
Then check the one that you know should be checked.
UPDATE dummy
SET SELECTED = 1
WHERE ID = 3;

Dynamic list for drop-down menu

In colunm "A" I have a list that will be filled up by the user; it starts at "A5" but I don't know where it will end.
In column "B" I'd like to make cells look like dropdown menus where items in the list will be the values from column "A".
And whenever the user adds a value to column "A" this should be automatically added to the list.
Create named range (say colA) with formula:
=$A$5:INDEX($A:$A,MATCH(2,1/($A:$A<>"")))
and then use Data validation with named range colA:
In Column A, set up your starting data list as a Table (select your list and then Insert/Table).
Give your new table a nice name (select the Table then go to Table Tools/Design/Table Name).
Tables in Excel automatically expand when a new value is added to an existing Table.
Next, select this same starting data list and create a Named Range. Go to Formulas/Define Name.
Give your list a Name (for example, "List"), and in Refers To enter your Table name. (e.g. type "=Table1" if that's the name of your Table)
I am assuming that for your Column B, you want Data Validation - it puts the dropdowns in each cell as you suggest.
Select the range of cells that you are going to validate, then go to Data/Data Validation.
Under Settings, choose Allow = List.
Under Source type the name of your Named Range that you set up in Column A. (e.g. type "=List").
Add an Input and Output message to your Validation (optional but helpful).
Click OK to close.
Credit to Chandoo.org where I learned this.

Saving a row in a many to many table with conditions

I have 3 tables that form a many to many relationship as illustrated in the following image.
How can I save an entry in the UsersByCompanies table between company number 1 and user number 2, following the following rules:
when we create a new entry between a user and a company, the IsEnabled attribute in UsersByCompanies must be set to 1 and any other rows where Companies.CompanyCode = 1 and Users.IDNumber = 2 must have their IsEnabled Attribute set to 0.
The DateCreated attribute in the new row must have the current date.
Sounds like you need an Insert Trigger and some default values:
When you insert into UsersByCompanies, use a Default Value on the IsEnabled column, and set an insert trigger function to perform an update to reset the IsEnabled attributes as you require.
Likewise, use a default value of getdate() for the DateCreated attribute.