Trigger for 1:m relationship - sql

I have 2 tables: customers and orders. How can I use trigger to create 1:M relationship?
I have next tables
CREATE TABLE Customer(
customer_id INT GENERATED BY DEFAULT AS IDENTITY,
customer_name VARCHAR2(50) NOT NULL,
datachange TIMESTAMP NOT NULL,
PRIMARY KEY(customer_id)
);
CREATE TABLE Orders(
order_id INT GENERATED BY DEFAULT AS IDENTITY,
customer_id INT NOT NULL,
PRIMARY KEY(order_id)
);
And I have to do a trigger instead of:
ALTER TABLE Orders add constraint FK_CUSTOMER_ID FOREIGN KEY (customer_id) REFERENCES Customer(customer_id);

here is an example how to create a trigger:
https://www.siteground.com/kb/mysql-triggers-use/
but relation is the best solution at this moment:
if there is no specific reason to complicate something, don't complicate it. Use simple and widely used solutions to avoid many problems in the future :-)
ps. I'm not sure if you are using MySQL or some other database because you didn't specify ...

If you look at trigger syntax. It clearly mentions
CREATE TRIGGER trigger_name
{BEFORE | AFTER} {INSERT | UPDATE| DELETE }
ON table_name FOR EACH ROW
trigger_body;
Can't find any trigger on CREATE TABLE.
Can you properly explain why the trigger needs to be fired after you create table?
Maybe you are misunderstanding the functions of a trigger

Related

Postgresql Foreign Key Actions - Delete Attribute and Change Other Attributes Related to This

I create 3 tables just like image. Each students can be enrolled multiple class I tried to build one to many relation.
What I want to do is, when a student is deleted from the "Student" table, the course in which the student is registered in the "Bridge" table returns to null. How can I do this operations with postgresql (pgAdmin 4), can you help me please? Thank you...
You are describing the on delete set null option to foreign keys constraints. The create table statement for bridge would look like:
create table bridge (
std_id int references students(std_id) on delete set null,
class_id int references class(class_id)
);
I am unsure that set null is your best pick for such a bridge table though. This leaves "gaps" in your data that do not make a lot of sense. on delete cascade would probably make more sense - and you could apply it to both foreign keys:
create table bridge (
std_id int references students(std_id) on delete cascade,
class_id int references class(class_id) on delete cascade
);
That way, the bridge table is properly cleaned up when any parent record is dropped. This also opens the way to set up a composite primary key made of both columns in the bridge table.

Create primary key for table with period (Temporal Validity) in Oracle SQL

I have a question regarding to primary key for Oracle Table with Period.
I have created two tables like following:
create table el_temporal_try( -- Parent Table
id number(10) not null,
ColumnA varchar(10),
constraint el_temporal_try_pk primary key (id),
period for valid_period
);
create table el_temporal_try_son( -- Son Table
id number(10) not null,
ColumnA varchar(10),
parent_id number(10),
constraint el_temporal_try_FY foreign key (parent_id) references el_temporal_try(id),
period for valid_period
);
This script gone through successfully. However I have problem with inserting data:
I have executed following two insert statements into the parent table:
1st: statement
insert into el_temporal_try
(id, columnA,valid_period_start, valid_period_end)
values
(1,'A',sysdate - 10, sysdate - 9);
Result:
1 row inserted.
2nd: statement
insert into el_temporal_try
(id, columnA,valid_period_start, valid_period_end)
values
(1,'B',sysdate - 8, sysdate - 7);
Result
ORA-00001: unique constraint (PBSVW.EL_TEMPORAL_TRY_PK) violated
I understand it is because of the "ID" column. However, my issues because this two rows are for a different period, should it be allowed?
I was intended to use this period for feature to capture the change history of a record as an alternative to flashback. However, does it means that I should not use primary key at this situation?
Thanks in advance!
The problem is related to the id column like you said. it's not possible to add the registry because the primary key is unique, then your second insert statement references the same ID from the first. You need to change the ID always you insert a line.
On Oracle 12c, you can use the identity like this link.
https://www.oracletutorial.com/oracle-basics/oracle-identity-column/
in another version, you can use sequence and trigger to do this.
https://chartio.com/resources/tutorials/how-to-define-an-auto-increment-primary-key-in-oracle/
Thanks for everyone's help on this. This most likely means I cannot use Primary Key/Foreign Key to maintain the referential integrity between the parent and son for my situation within a particular timestamp, but I have to go for something else.
Thanks a lot!

How can set unique key checking by another table

i have create three tables: supplier, item and purchase. supplier id has relation with item table and item id has relation with purchase table. I do not want to insert itemid on purchase table in same supplier item. How can I set constraint?
CREATE TABLE csupplier(
supid NUMBER(10) PRIMARY KEY ,
supname VARCHAR2(30)
);
CREATE TABLE ctitem(
itemid NUMBER(10) PRIMARY KEY,
itemname VARCHAR2(50),
supid NUMBER(10)
);
ALTER TABLE CTITEM
ADD CONSTRAINT CTITEM_FK1 FOREIGN KEY(SUPID )REFERENCES CSUPPLIER(SUPID );
CREATE TABLE cPurchase(
purchaseid NUMBER(10) PRIMARY KEY,
itemid NUMBER(10),
purchaseqty NUMBER(10)
);
ALTER TABLE CPURCHASE
ADD CONSTRAINT CPURCHASE_FK1 FOREIGN KEY(ITEMID )REFERENCES CTITEM(ITEMID )
i don not want insert item-1 and item-3 in a same time under purchase
The problem is Oracle does not understand concept of at the same time. It understands transactions, it understands DML statements, it understands unique keys. So we need to frame your question in terms Oracle can understand: for instance, a given purchase cannot have more than one item from the same supplier.
Your first problem is that your data model can't support such a rule. Your cpurchase table has a primary key of purchaseid which means you have one record per item purchased. There is no set of purchased items against which we can enforce a rule. So, the first thing is to change the data model:
CREATE TABLE cPurchase(
purchaseid NUMBER(10) PRIMARY KEY );
CREATE TABLE cPurchaseItem(
purchaseid NUMBER(10),
itemid NUMBER(10),
purchaseqty NUMBER(10)
);
ALTER TABLE CPURCHASEITEM
ADD CONSTRAINT CPURCHASEITEM_PK PRIMARY KEY(PURCHASEID,ITEMID);
ALTER TABLE CPURCHASEITEM
ADD CONSTRAINT CPURCHASEITEM_FK1 FOREIGN KEY(PURCHASEID )REFERENCES CPURCHASE;
ALTER TABLE CPURCHASE
ADD CONSTRAINT CPURCHASE_FK2 FOREIGN KEY(ITEMID )REFERENCES CTITEM(ITEMID );
Now we have a header-detail structure which assigns multiple items to one purchase, which means we can attempt to enforce the rule.
The next problem is that supplierid is not an attribute of cpurchaseitem. There is no way to build a check constraint on a table or column which executes a query on another table. What you are after is a SQL Assertion, which is a notional construct that would allow us to define such rules. Alas Oracle (nor any other RDBMS) supports Assertions at the moment.
So that leaves us with three options:
Go procedural, and write a transaction API which enforces this rule.
Denormalise cpurchaeitem to include supplierid then build a unique constraint on (purchaseid, supplierid). You would need to populate supplierid whenever you populate cpurchaseitem.
Write an after statement trigger:
(Warning: this is coded wildstyle and may contain bugs and/or compilation errors.)
create or replace trigger cpurchaseitem_trg
after insert or update on cpurchaseitem
declare
rec_count number;
begin
select count(*)
into rec_count
from cpurchaseitem pi
join citem I on pi.itemid = i.itemid
group by pi.purchaseid, i.supplierid having count(*) > 1;
if rec_count > 0 then
raise_application_error(-20000
, 'more than one item for a supplier!');
end if;
end;
Frankly none of these solutions is especially appealing. The API is a solid solution but open to circumvention. The trigger will suffer from scaling issues as the number of purchases grows over time (although this can be mitigated by writing a compound trigger instead, left as an exercise for the reader). Denormalisation is the safest (and probably most performative) solution, even though it's not modelling best practice.
There are 2 solutions to your problem:
1. Alter the table cPurchase and add the supid column in the table. and make the unique key on this column. This will solve your problem.
CREATE TABLE cPurchase(
purchaseid NUMBER(10) PRIMARY KEY,
itemid NUMBER(10),
purchaseqty NUMBER(10),
supid NUMBER(10) UNIQUE KEY
);
If alter is not possible on this table, write a row level, Before Insert/update trigger. In this trigger write the logic to find the Supid based on the Item_id ctitem and them find any item on this supplier exists in your purchase table.
CREATE [ OR REPLACE ] TRIGGER SUP_CHECK
BEFORE INSERT
ON cPurchase
FOR EACH ROW
DECLARE
L_COUNT NUMBER;
BEGIN
SELECT COUNT(*) INTO L_COUNT
FROM cPurchase c
WHERE C.itemid in (Select itemid from ctitem ct where ct.supid = (Select supid
from ctitem where itemid = :new.itemid) );
EXCEPTION
WHEN ...
-- exception handling
END;

CREATE TABLE statement of looped ER Table

So i need to create CREATE TABLE statement of this ER Table. I know how normally create those statements but I don't know how to do it with these looped ones. I need your help with this.
All i have about this table is this;
Q2
Convert the following ER diagram into relational model. Write the “CREATE TABLE”
statements. Don’t forget to specify the primary keys and foreign keys.
In MySql syntax:
create table employee
eid int not null primary key,
name varchar not null,
reports int foreign key references employee(eid) on update cascade on delete set null
Note: this implements 1:N., thus a hierarchy.
My best guess at the moment would be something along the lines of.
USE [database_name]
GO
CREATE TABLE t_employee (
eid INT IDENTITY(1,1)
, name NVARCHAR(50) );
CREATE TABLE t_reports (
report_id INT IDENTITY (1,1)
, eid INT );
ALTER TABLE t_reports
ADD FOREIGN KEY (eid) REFERENCES t_employee(eid);
To clarify, this is SQL Server syntax, but it should work on the common RMDBs except for Oracle which uses almost SQL syntax.

Does oracle provide a built-in currency table for me to use as constraints?

I'm creating a table in Oracle 11g like this:
CREATE TABLE EXAMPLE (
ID VARCHAR2(10) PRIMARY KEY,
NAME VARCHAR2(100),
SHORT VARCHAR2(50),
CURRENCY CHAR(3)
);
Is it possible to create a foreign key constraint or even a check constraint on CURRENCY to a built-in Oracle table that contains the ISO currencies?
Not having a great understanding of databases I also take as input other solutions that might be out there, however I do not want to maintain my own table for this, if it's too much work, I'll live with user errors.
Thanks.
You can get a list of ISO currencies from a built in view in oracle:
select utl_i18n.GET_DEFAULT_ISO_CURRENCY(value) iso_cur
from v$nls_valid_values
where parameter = 'TERRITORY'
But as Nuno Guerreiro said, you'll need to create a table from these results and add a foreign key to the new table.
Note: Edited to include #A.B.Cade's suggestion.
Unfortunately you can't directly add a constraint, as the currencies data is available through a system a view. You can, however, create your own table with that information and then create the foreign key. Here's an example of how you can do it.
CREATE TABLE currencies (
country VARCHAR2(30) PRIMARY KEY,
currency VARCHAR2(3) NOT NULL
);
INSERT INTO currencies
SELECT value country, utl_i18n.get_default_iso_currency(value) currency
FROM v$nls_valid_values
WHERE parameter = 'TERRITORY';
CREATE INDEX currencies_iso_idx ON currencies(currency) COMPUTE STATISTICS;
ALTER TABLE example ADD CONSTRAINT example_currency_fk FOREIGN KEY (currency)
REFERENCES currencies(currency);
The example above includes an index on the currency value, as I suspect that will what you'll be querying on.
Actually I don't understand what do you mean by "default Oracle table that contains ISO currencies" (do you mean Oracle PeopleSoft CURRENCY_CD_TBL table?), but in general you can alter your table after creation to add foreign key constraint.
Here is an example:
ALTER TABLE EXAMPLE
ADD CONSTRAINT fk_currency
FOREIGN KEY (CURRENCY)
REFERENCES put_parent_table_name_here(_corresponding_field_name_in_perent_table);
You also can add constraint definition into CREATE TABLE statement.
Here is an example:
CREATE TABLE EXAMPLE (
ID VARCHAR2(10) PRIMARY KEY,
NAME VARCHAR2(100),
SHORT VARCHAR2(50),
CURRENCY CHAR(3),
CONSTRAINT fk_currency
FOREIGN KEY (CURRENCY)
REFERENCES put_parent_table_name_here(_corresponding_field_name_in_perent_table)
);