About restrictive record creation in a child table. (Oracle Forms Builder) - oracle

I created a form where i add records to a child table. However I don't want people to be able to edit the secondary key, only select it from the list of primary keys of the parent or something along those lines. How could i do that?
The tables:
CREATE TABLE CHAMPIONS (CNAME VARCHAR2(15) NOT NULL, PRICELEVEL NUMBER(1) NOT NULL, ROLE VARCHAR2(10) NOT NULL, HPLEVEL NUMBER(2) NOT NULL, ATKLEVEL NUMBER(2) NOT NULL, MAGICLEVEL NUMBER(2) NOT NULL, DIFFLEVEL NUMBER(2) NOT NULL);
CREATE TABLE SKINS (SNAME VARCHAR2(20) NOT NULL, CNAME VARCHAR2(15) NOT NULL, PRICELEVEL NUMBER(1) NOT NULL);
ALTER TABLE Champions ADD CONSTRAINT pk_Champions PRIMARY KEY (CNAME);
ALTER TABLE Skins ADD CONSTRAINT fk_Skins FOREIGN KEY (CNAME) REFERENCES champions(CNAME);

Too less information to be able to give an answer, but I can give it a try.
You can have LOVs created in the detail table and have that LOV driven off of the parent tables primary key, also the text item with which you would be linking the LOV you need to put a WHEN-VALIDATE-ITEM trigger with the same query as in the LOVs RECORD GROUP so that in case the user types instead of using the LOV you can validate the input and then alert them in case of invalid input and fetch the correct master primary key in case of correct value entered.
Below is how the datablock with the LOV buttons look like-
And below is the Trigger on the STORE item in the datablock-
You can code the RG similarly as the query in the trigger considering your master table in the query.

The simplest way to get this functionality is to create a LOV based on champions.cname and attach it to item form column skins.cname (Please refer the Forms help if you are not familiar with creating LOV:s). Then set the item property 'Validate from list' of item skins.cname to Yes. This will validate all entered values against the existing cname values.

Related

MODIFY or ADD to add NOT NULL constraint to a column? Oracle sql

ORDERS table in the Oracle Database:
ORDERS
ORDER_ID NOT NULL NUMBER(4)
ORDATE_DATE DATE
CUSTOMER_ID NUMBER(3)
ORDER_TOTAL NUMBER(7,2)
The ORDERS table contains data and all orders have been assigned a customer ID. I'm trying to add a NOT NULL constraint to the CUSTOMER_ID column. Would I use MODIFY CONSTRAINT or ADD CONSTRAINT? I was told you have to drop the constraint and ADD the new one, but if there is no existing constraint to Customer ID number, would it be MODIFY?
alter table orders modify customer_id not null;
Just MODIFY the column:
alter table orders modify customer_id not null;
Alternatively, you could add an [overkill] constraint in the form:
alter table orders add constraint nn1 check (customer_id is not null);
Just use the first form.
As a side note, some databases (such as Oracle) consider those two constraint different and somewhat separate: the former is a column constraint, while the latter is a table constraint. Oracle keeps track in case you drop one, while the other is still in effect.

Contraint to set one column as the sum of two others automatically

I'm wondering is it possible to use a constraint to set the value of one column to be sum of two others. For example given the following tables:
CREATE TABLE Room (
Room_Num NUMBER(3),
Room_Band_ID NUMBER(2),
Room_Type_ID NUMBER(2),
Room_Price NUMBER(4),
PRIMARY KEY (Room_Num),
FOREIGN KEY(Room_Band_ID)
REFERENCES Room_Band(Room_Band_ID),
FOREIGN KEY(Room_Type_ID)
REFERENCES Room_Type(Room_Type_ID)
);
CREATE TABLE Booking (
Booking_ID NUMBER(10) NOT NULL,
GuestID NUMBER(4) NOT NULL,
StaffID NUMBER(2) NOT NULL,
Payment_ID NUMBER(4) NOT NULL,
Room_Num NUMBER(3) NOT NULL,
CheckInDate DATE NOT NULL,
CheckOutDate DATE NOT NULL,
Booking NUMBER(2) NOT NULL,
Price NUMBER(4),
PRIMARY KEY (Booking_ID),
FOREIGN KEY(GuestID)
REFERENCES Guest(GuestID),
FOREIGN KEY(StaffID)
REFERENCES Staff(StaffID),
FOREIGN KEY(Payment_ID)
REFERENCES Payment(Payment_ID),
FOREIGN KEY(Room_Num)
REFERENCES Room(Room_Num)
);
I know it is possible to do something like:
Constraint PriceIs CHECK (Booking.Price=(Room.Room_Price*
(Booking.CheckOutDate - Booking.CheckInDate)));
Is it also possible to set up a constraint that doesn't just ensure that the price is correct, but to calculate the price automatically into the price field for the relevant tuple?
Update,
So I've tried to set up a trigger as follows:
CREATE OR REPLACE trigger PriceCompute
AFTER INSERT ON Booking
FOR each row
BEGIN
UPDATE Booking
SET
SELECT (Room.Room_Price*(Booking.CheckOutDate - Booking.CheckInDate))
INTO
Booking.Price
FROM Booking
JOIN ROOM ON Booking.Room_Num = Room.Room_Num
END;
/
But I'm getting the following errors back:
Can anyone see where I'm going astray here, as its beyond me.
Yes, you can. Here are your options. Listed in order of my personal preference:
You can have a table without this column. And create a view that will be calculating this column on a fly.
You may use oracle virtual columns
create table Room (
...
price NUMBER GENERATED ALWAYS AS (room_price*(checkOut-checkIn)) VIRTUAL,
...)
You may use actual column (same as 2, per Dave Costa):
create table Room (
...
price AS (room_price*(checkOut-checkIn)),
...)
You can write trigger to populate it (like Mat M suggested)
You can write stored procedure, but it will be an overkill in this situation
I think you would have to put a trigger on both tables for whenever the price value of the room is changed or the checkout/in dates are changed, it will update the PriceIs field from your calculation.
If you don't need the calculated portion stored in an actual field, you can always create a view that calculates it whenever you look at the view.
I think the better solution is to use a view that calculates the value on the fly. But regarding your attempt to create a trigger, you should use :new.<column_name> to refer to the values being inserted into the Booking table. You don't need to perform updates and queries on that table to get or modify the values in the row that is being inserted*. You just refer to them as variables. So you would want to do something like:
SELECT (Room.Room_Price*(:new.CheckOutDate - :new.CheckInDate))
INTO
:new.Price
FROM ROOM WHERE :new.Room_Num = Room.Room_Num
*In fact, you can't perform queries or updates on the table whose modification invoked the trigger in the first place. You would get the infamous "mutating table" error if your trigger actually compiled and ran.

Trigger for incrementing a date and inserting into another table

I want to create a trigger, in Oracle. When the dateOrdReceived in my order table is updated or inserted the trigger takes this date whatever it may be and updates it by 14 days into another table productList ordDateDelivery so that it equals to
dateOrdReceived + 14 days = new ordDateDelivery
I did have a couple of attempts and guessed I'd need a query which would join my two tables. I also learned that maybe using DATEADD would allow me add 14 days but altogether I can't quite get it right.
My trigger attempt
`CREATE OR REPLACE TRIGGER "PRODUCTLIST_DATE_DELIVERY"
BEFORE
insert or update on "PRODUCTLIST"
for each row
begin
select p.dateOrdRecieved, o.ordDateDelivery
from productList p JOIN orders o
ON p.ordID = o.ordID;
new.OrdDateDelivery := DATEADD(day,14,new.p.dateOrdRecieved)
end;
/
ALTER TRIGGER "PRODUCTLIST_DELIVERY_DATE" ENABLE
and my tables for this trigger are as follows
PRODUCTLIST TABLE
CREATE TABLE "PRODUCTLIST"
( "ORDID" NUMBER(3,0) NOT NULL ENABLE,
"PRODUCTID" NUMBER(3,0) NOT NULL ENABLE,
"QUANTITY" NUMBER(4,2) NOT NULL ENABLE,
"ORDDATEDELIVERY" DATE,
"DISCOUNT" NUMBER(3,0),
"TOTALCOST" NUMBER(4,2),
CONSTRAINT "PK_PRODUCTLIST" PRIMARY KEY ("ORDID", "PRODUCTID") ENABLE
)
/
ALTER TABLE "PRODUCTLIST" ADD CONSTRAINT "FK_ORDERS" FOREIGN KEY ("ORDID")
REFERENCES "ORDERS" ("ORDID") ENABLE
/
ALTER TABLE "PRODUCTLIST" ADD CONSTRAINT "FK_PRODUCTS" FOREIGN KEY ("PRODUCTID")
REFERENCES "PRODUCT" ("PRODUCTID") ENABLE
/
ORDERS TABLE
CREATE TABLE "ORDERS"
( "ORDID" NUMBER(3,0) NOT NULL ENABLE,
"DATEORDRECIEVED" DATE,
"CUSID" NUMBER(3,0) NOT NULL ENABLE,
PRIMARY KEY ("ORDID") ENABLE
)
/
ALTER TABLE "ORDERS" ADD CONSTRAINT "FK_CUSTOMER" FOREIGN KEY ("CUSID")
REFERENCES "CUSTOMER" ("CUSID") ENABLE
/
DATEADD() is not an Oracle function... Oracle's datetime arithmetic is based around the day. If you add 1 to a date it increments the date by one day, adding 1.5 by 36 hours etc.
Now, your trigger.
You can't automatically update or insert a record into another table. The trigger is "on" one table, which means you need to create the DML in order to add or update it into that table.
update productlist
set dateOrdRecieved = :new.OrdDateDelivery + 14
where ordid = :new.ordid
The :new. here references the new data of the table on which the trigger is on. It's a specific "variable" that you can access rather than a general concept of what you're trying to achieve. You can't use it to assign data to other tables directly, though you can use it as a means of doing so.
Next you need to consider where your trigger is. You're looking to update PRODUCTLIST whenever ORDERS is changed, this means that the trigger needs to be on the table ORDERS.
create or replace trigger productlist_date_delivery
before insert or update on orders
for each row
begin
update productlist
set OrdDateDelivery = :new.dateOrdRecieved + 14
where ordid = :new.ordid;
end;
/
Notice a few extra differences to your own:
I use :new. instead of new.
I'm not selecting from the table; there's no need to do this as the data is already available. It's also impossible as you're selecting data that Oracle's trying to update, it forbids this to ensure integrity.
I haven't used cased identifiers. There's no need to do this; Oracle upper-cases everything by default. It's also really painful if everything's not upper case as you have to remember
Every statement ends in a semi-colon.
If you're having problems I recommend Tech on the Net, it has a good basic guide. As always though, there's the documentation on the CREATE TRIGGER statement.

Searching in the parent table with checkboxes (Oracle Forms Builder)

Where could I find any info on that.
a)I'll need to select which column is being searched
b)Select what data will be displayed with check boxes
c)If the selected column(in which you search) is the primary key column, then the form will also display the child table check boxes which, if checked, will display the columns along with the checked parent table columns.
The tables:
CREATE TABLE CHAMPIONS (
CNAME VARCHAR2(15) NOT NULL,
PRICELEVEL NUMBER(1) NOT NULL,
ROLE VARCHAR2(10) NOT NULL,
HPLEVEL NUMBER(2) NOT NULL,
ATKLEVEL NUMBER(2) NOT NULL,
MAGICLEVEL NUMBER(2) NOT NULL,
DIFFLEVEL NUMBER(2) NOT NULL
);
CREATE TABLE SKINS (
SNAME VARCHAR2(20) NOT NULL,
CNAME VARCHAR2(15) NOT NULL,
PRICELEVEL NUMBER(1) NOT NULL);
ALTER TABLE Champions ADD CONSTRAINT pk_Champions PRIMARY KEY (CNAME);
ALTER TABLE Skins ADD CONSTRAINT fk_Skins FOREIGN KEY (CNAME) REFERENCES champions(CNAME);
I don't really care how this is implemented since i don't know which way is possible. Since it's just a 1-1 relationship, some sort of hiding might work.
if the pressed button is cname(the primary key) the first result table will of course have only one row while the second result table will be populated by the data associated with the selected primary key. If any other button is pressed the other table isn't even displayed however the first one might have multiple rows displayed. The columns that are displayed in the results depend on the check boxes
If you don't want to repeat the champion data displayed, create two separated database blocks, and add a relation between them.
If you want to display all data in one multi-row block, you will need a view that joins the data from the two tables.
Your search options will be a non-database block. When you click in the search button, you will need to change the default_where of the blocks, adding the value searched according to the field. For this, you will need to add the trigger pre-query. Something like:
trigger of search button
begin
go_block('champions_block');
execute_query; -- this triggers pre-query of champions_block
end;
trigger pre-query
if :search.search_text is not null then
-- this changes the where of your block
set_block_property('champions_block',default_where, 'cname like %'||:search.search_text||'%');
--
else
-- remove previous where
set_block_property('champions_block',default_where, '');
end if;
The show / hide of fields is more complicated, you will need to show / hide the items using:
set_item_property('name_of_block.name_of_item', visible, property_true); -- false to hide
And also will need to adjust the position of the other fields:
set_item_property('name_of_block.name_of_item', position, pos_x, pos_y);

Trigger to enter deleted entries to a new table - SQL plus

I am trying to create a trigger which will enter values into a table terminated_employees when we delete values from the nm_employees table. I have written the trigger but it does not work. Is my trigger format right? Any ideas?
CREATE TABLE nm_departments(
dept2 varchar(20),
CONSTRAINT empPK PRIMARY KEY (dept2)
);
CREATE TABLE nm_employees(
name varchar(20),
dept varchar(20),
CONSTRAINT departments FOREIGN KEY (dept) REFERENCES nm_departments (dept2)ON DELETE CASCADE
);
CREATE TABLE terminated_employees(
te_name varchar(20),
te_dept varchar(20)
);
CREATE TRIGGER term_employee AFTER DELETE ON nm_employee
FOR EACH ROW
BEGIN
INSERT INTO terminated_employees (NEW.te_name, NEW.te_dept) VALUES (OLD.name,OLD.dept)
END;
You should not be specifying the NEW. on the column names of your INSERT statement. These are the columns in the terminated_employees table, NOT the new values. i.e.
INSERT INTO terminated_employees (te_name, te_dept)
VALUES (OLD.name,OLD.dept)
You can use show errors (or show err) in SQL*Plus to see the exact error.
You have a number of problems:
Wrong table name on create trigger (missing the s)
Missing ; after instert statement
The OLD. need to have : prefix. i.e. :OLD.name

Resources