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

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.

Related

Oracle primary key with multiple column

I have seen the below create table statement :
create table cruise_orders
(cruise_order_id number,
order_date date,
constraint pk_or_id primary key (cruise_order_id,order_date));
so here the primary_key has two columns. But in case if I try the below statement and try to alter the table cruise_orders and add the column order_date to the primary key pk_or_id it throws an error saying "A table can have only one Primary key".
So how does it works with the first statement ? and why it doesn't work with the second alter statement ?
create table cruise_orders
(cruise_order_id number,
order_date date,
constraint pk_or_id primary key (cruise_order_id));
If you want it so that the cruise_order_id must be unique and, separately, that the order_date must be unique then use two constraints:
CREATE TABLE cruise_orders(
cruise_order_id NUMBER,
order_date DATE,
CONSTRAINT cruise_orders__or_id__pk PRIMARY KEY(cruise_order_id)
);
ALTER TABLE cruise_orders ADD CONSTRAINT cruise_orders__order_date__u UNIQUE(order_date);
If you really do want to have a single constraint with both columns the drop the first constraint and create a second with both columns:
CREATE TABLE cruise_orders(
cruise_order_id NUMBER,
order_date DATE,
CONSTRAINT cruise_orders__or_id__pk PRIMARY KEY(cruise_order_id)
);
ALTER TABLE cruise_orders DROP CONSTRAINT cruise_orders__or_id__pk;
ALTER TABLE cruise_orders ADD CONSTRAINT cruise_orders__coi__od__pk
PRIMARY KEY(cruise_order_id, order_date);
Then you will be able to have duplicate cruise_order_id values provided the order_date is different and vice-versa.

Create table as select statement primary key in oracle

Is it possible to specify which is the primary key on creating table as select statement? My aim is to include the declaration of primary key on the create table not modifying the table after the creation.
CREATE TABLE suppliers
AS (SELECT company_id, address, city, state, zip
FROM companies
WHERE company_id < 5000);
Yes, it's possible. You would need to specify columns explicitly:
CREATE TABLE suppliers (
company_id primary key,
address,
city,
state,
zip
)
AS
SELECT company_id, address, city, state, zip
FROM companies
WHERE company_id < 5000;
Here is a demo
Note: in this case primary key constraint will be given a system-generated name. If you want it to have a custom name you'd have to execute alter table suppliers add constraint <<custom constraint name>> primary key(<<primary_key_column_name>>) after executing(without primary key specified) CREATE TABLE suppliers.. DDL statement.
Yes, it's possible.You can try referring below example.
create table student (rollno ,student_name,score , constraint pk_student primary key(rollno,student_name))
as
select empno,ename,sal
from emp;
You can create Suppliers table explicitly and if any column have primary key in companies table, then copy that structure from companies table.
Or
Create a same column defining primary key that you want and copy that column from companies table!

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.

how to modify a constraint in sql plus?

I have created a table as follows:
create table emp( emp_id number(5) primary key
, emp_name varchar(20) not null
, dob date );
After the table has been created how would I change the constraint not null to unique or any other constraint in SQL*Plus?
You don't change a constraint from one type to another. You can add a unique constraint to the table
ALTER TABLE emp
ADD ( COSTRAINT uk_emp_name UNIQUE( emp_name ) );
That is independent of whether emp_name is allowed to have NULL values.
Just use ALTER TABLE command. For details look here: http://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_3001.htm#i2103817
We cant be able to modify the already added constraint. Just we have to drop the constraint and add the new one with the same name, but add it with the necessary changes.
ALTER TABLE table_name drop constraint contraint_name;
alter table tablename add constraint containt_name CHECK (column_name IN (changes in the contraint)) ENABLE;

Check Constraint in Oracle

I have been struggling to figure out a way to insert check such that it won't allow payment date to be earlier than the invoice date. basically, I have two table: invoice and payment. so I want a check constraint to enter into payment a date that is before the purchase date in invoice table. The invoice_id in Invoice table is a FK in payment table. Any help?
A check constraint can only look at columns on the table it is defined on.
You'll need to use a TRIGGER to do this.
One approach might be to duplicate the purchase date in the payment table, add a second unique constraint over the combination of invoice_id + purchase date, then modify the FK constraint to include it. Then, you can have your row-level constraint. e.g.
CREATE TABLE invoices
( invoice_id NUMBER NOT NULL
, purchase_date DATE NOT NULL
, CONSTRAINT invoice_pk PRIMARY KEY (invoice_id)
, CONSTRAINT invoice_uk UNIQUE (invoice_id, purchase_date)
);
CREATE TABLE payments
( payment_id NUMBER NOT NULL
, invoice_id NUMBER NOT NULL
, purchase_date DATE NOT NULL
, payment_date DATE NOT NULL
, CONSTRAINT payment_pk PRIMARY KEY (payment_id)
, CONSTRAINT payment_invoice_fk
FOREIGN KEY (invoice_id, purchase_date)
REFERENCES invoices (invoice_id, purchase_date)
, CONSTRAINT payment_date_ck
CHECK (payment_date >= purchase_date)
);
Downside: updating invoices.purchase_date becomes a bit tricky.

Resources