Unique constraint on two database columns with reverse direction - sql

I'm stuck upon a following problem: Let's say I have a table with relations to itself:
CREATE TABLE ITEM (
ID NUMBER(18) PRIMARY KEY,
NAME VARCHAR2(100 CHAR) NOT NULL
);
ALTER TABLE ITEM ADD CONSTRAINT PK_ITEM PRIMARY KEY (ID);
CREATE TABLE ITEM_RELATION (
FIRST_ITEM_ID NUMBER(18) NOT NULL,
SECOND_ITEM_ID NUMBER(18) NOT NULL,
RELATION_TYPE VARCHAR2(1) NOT NULL
);
ALTER TABLE ITEM_RELATION ADD CONSTRAINT PK_ITEM_RELATION PRIMARY KEY (FIRST_ITEM_ID, SECOND_ITEM_ID, RELATION_TYPE);
--ALTER TABLE ITEM_RELATION ADD CONSTRAINT UK_ITEMS UNIQUE (FIRST_ITEM_ID, SECOND_ITEM_ID, RELATION_TYPE);
ALTER TABLE ITEM_RELATION ADD CONSTRAINT FK_FIRST_ITEM FOREIGN KEY (FIRST_ITEM_ID) REFERENCES ITEM(ID);
ALTER TABLE ITEM_RELATION ADD CONSTRAINT FK_SECOND_ITEM FOREIGN KEY (SECOND_ITEM_ID) REFERENCES ITEM(ID);
Now let's say, I wan't the relation to be directional, that is if item 1 has relation to item 2 of certain type, the item 2 shouldn't have the same relation to item 1.
That is, the following should not be permitted:
INSERT INTO ITEM (ID, NAME) VALUES (1, 'Item 1');
INSERT INTO ITEM (ID, NAME) VALUES (2, 'Item 2');
INSERT INTO ITEM_RELATION(FIRST_ITEM_ID, SECOND_ITEM_ID, RELATION_TYPE) VALUES (1, 2, 'R');
INSERT INTO ITEM_RELATION(FIRST_ITEM_ID, SECOND_ITEM_ID, RELATION_TYPE) VALUES (2, 1, 'R');
It means that the table ITEM_RELATION defines a direction of this connection, and it shouldn't be allowed to add a reversed relation.
Is it possible with Oracle DB?

You can do this with a unique index. In Oracle, you can use functions in indexes, so this will work:
create unique index unq_item_relation_3 on
item_relation(RELATION_TYPE ,
least(FIRST_ITEM_ID, SECOND_ITEM_ID),
greatest(FIRST_ITEM_ID, SECOND_ITEM_ID)
);
You could get the same effect with a check constraint, by requiring that FIRST_ITEM_ID be less than SECOND_ITEM_ID:
alter table item_relation add constraint chk_item_relation_2
check ((FIRST_ITEM_ID < SECOND_ITEM_ID);
However, this requires that the items be inserted in a particular order.

Related

Even with complete and readable statements, an error occurs: SQL Error [900] [42000]: ORA-00900: invalid SQL statement

I have two tables created in my Oracle database: the table 'responsible' (which has the id and description of the responsible) and the table 'ident' (which has id's of three types of expenses).
Below, I am trying to create a script in which:
Add values to the columns of the 'responsible';
create a 'type_responsible' table, and insert values into it;
create a relationship table called 'responsible_by_type', which, using the data from the table 'responsible', 'ident' and 'responsible_type' establishes one relationship between them.
These changes in data type to primary key or foreign key are attempts to get the bank to recognize the fields as relatable.
I get the error: 'SQL Error [900] [42000]: ORA-00900: invalid SQL statement'. Even if I execute one instruction at a time, which makes no sense.
I really don't know where my mistake is. Since I can't run the script, I can't know if the script allows me to reach my goal. Could someone help me?
<--Table RESPONSIBLE-->
INSERT INTO RESPONSIBLE(RESPONSIBLE_ID, RESPONSIBLE_DESC) VALUES (1, 'payer1');
INSERT INTO RESPONSIBLE(RESPONSIBLE_ID, RESPONSIBLE_DESC) VALUES (2, 'payer2');
ALTER TABLE RESPONSIBLE ADD CONSTRAINT PK_RESPONSIBLE_ID PRIMARY KEY (RESPONSIBLE_ID);
ALTER TABLE RESPONSIBLE ADD CONSTRAINT UNIQUE_RESPONSIBLE_DESC UNIQUE (RESPONSIBLE_DESC);
<--Table IDENT-->
<--OPTION ONE-->
ALTER TABLE IDENT ADD CONSTRAINT pk_RESPONSIBLES_TYPE_IDS primary key(RESPONSIBLE_DEBTS_ID, RESPONSIBLE_ASSETS_ID, RESPONSIBLE_EXPENSES_ID);
<--OPTION TWO-->
ALTER TABLE IDENT ADD CONSTRAINT FK_RESPONSIBLE_DEBTS_ID FOREIGN KEY (RESPONSIBLE_DEBTS_ID);
ALTER TABLE IDENT ADD CONSTRAINT FK_RESPONSIBLE_ASSETS_ID FOREIGN KEY (RESPONSIBLE_ASSETS_ID);
ALTER TABLE IDENT ADD CONSTRAINT FK_RESPONSIBLE_EXPENSES_ID FOREIGN KEY (RESPONSIBLE_EXPENSES_ID);
<--Table RESPONSIBLE_TYPE-->
CREATE TABLE RESPONSIBLE_TYPE(RESPONSIBLE_TYPE_ID NUMBER(10), RESPONSIBLE_TYPE_DESC VARCHAR(100));
INSERT INTO RESPONSIBLE_TYPE(RESPONSIBLE_TYPE_ID, RESPONSIBLE_TYPE_DESC) VALUES (1, 'Assets');
INSERT INTO RESPONSIBLE_TYPE(RESPONSIBLE_TYPE_ID, RESPONSIBLE_TYPE_DESC) VALUES (2, 'Expenses');
INSERT INTO RESPONSIBLE_TYPE(RESPONSIBLE_TYPE_ID, RESPONSIBLE_TYPE_DESC) VALUES (3, 'Debts');
ALTER TABLE RESPONSIBLE_TYPE ADD CONSTRAINT PK_RESPONSIBLE_TYPE_ID PRIMARY KEY (RESPONSIBLE_TYPE_ID);
<--Table RESPONSIBLE_BY_TYPE-->
CREATE TABLE RESPONSIBLE_BY_TYPE(RESPONSIBLE_ID NUMBER(10) NOT NULL, RESPONSIBLE_EXPENSES_ID NUMBER(10) NOT NULL,
RESPONSIBLE_ASSETS_ID NUMBER(10) NOT NULL, RESPONSIBLE_DEBTS_ID NUMBER(10) NOT NULL, RESPONSIBLE_DESC VARCHAR(100), RESPONSIBLE_TYPE VARCHAR(100),
CONSTRAINT FK_RESPONSIBLE_BY_TYPE FOREIGN KEY(RESPONSIBLE_ID) REFERENCES RESPONSIBLE(RESPONSIBLE_ID),
CONSTRAINT FK_RESPONSIBLE_BY_TYPE FOREIGN KEY(RESPONSIBLE_EXPENSES_ID) REFERENCES IDENT(RESPONSIBLE_EXPENSES_ID),
CONSTRAINT FK_RESPONSIBLE_BY_TYPE FOREIGN KEY(RESPONSIBLE_ASSETS_ID) REFERENCES IDENT(RESPONSIBLE_ASSETS_ID),
CONSTRAINT FK_RESPONSIBLE_BY_TYPE FOREIGN KEY(RESPONSIBLE_DEBTS_ID) REFERENCES IDENT(RESPONSIBLE_DEBTS_ID),
CONSTRAINT FK_RESPONSIBLE_BY_TYPE FOREIGN KEY(RESPONSIBLE_TYPE) REFERENCES RESPONSIBLE_TYPE(RESPONSIBLE_TYPE),
CONSTRAINT FK_RESPONSIBLE_BY_TYPE FOREIGN KEY(RESPONSIBLE_DESC) REFERENCES RESPONSIBLE(RESPONSIBLE_DESC);
In the first steps it was running. From the moment I created the table 'responsible_by_type' and started changing the data types of the other tables, I couldn't do anything anymore.
Now, even when I execute a simple insert instruction, I get the error I mentioned above.
This works from Oracle SQL Developer
-- ******************* Existing Table RESPONSIBLE - you don't need to create it ***************************
--CREATE TABLE RESPONSIBLE
-- (
-- RESPONSIBLE_ID NUMBER(10),
-- RESPONSIBLE_DESC VARCHAR2(100)
-- );
-- -------------- Alter table --------------------
ALTER TABLE RESPONSIBLE ADD CONSTRAINT pk_responsible_id PRIMARY KEY (RESPONSIBLE_ID);
ALTER TABLE RESPONSIBLE ADD CONSTRAINT unique_responsible_desc UNIQUE (RESPONSIBLE_DESC);
-- ---------- I n s e r t s ----------------
INSERT INTO RESPONSIBLE(RESPONSIBLE_ID, RESPONSIBLE_DESC) VALUES (1, 'payer1');
INSERT INTO RESPONSIBLE(RESPONSIBLE_ID, RESPONSIBLE_DESC) VALUES (2, 'payer2');
-- ******************* Existing Table IDENT - you don't need to create it ***************************
-- CREATE TABLE IDENT
-- (
-- RESPONSIBLE_DEBTS_ID NUMBER,
-- RESPONSIBLE_ASSETS_ID NUMBER,
-- RESPONSIBLE_EXPENSES_ID NUMBER
-- );
-- -------------- Alter table --------------------
ALTER TABLE IDENT ADD CONSTRAINT pk_responsibles_type_ids
PRIMARY KEY(RESPONSIBLE_DEBTS_ID, RESPONSIBLE_ASSETS_ID, RESPONSIBLE_EXPENSES_ID);
-- *************** New Table RESPONSIBLE_TYPE ***************************
CREATE TABLE RESPONSIBLE_TYPE
(
RESPONSIBLE_TYPE_ID NUMBER(10),
RESPONSIBLE_TYPE_DESC VARCHAR(100),
CONSTRAINT pk_responsible_type_id PRIMARY KEY (RESPONSIBLE_TYPE_ID)
-- option 2 -- PK(RESPONSIBLE_TYPE_ID, RESPONSIBLE_TYPE_DESC)
);
-- ---------- I n s e r t s ----------------
INSERT INTO RESPONSIBLE_TYPE(RESPONSIBLE_TYPE_ID, RESPONSIBLE_TYPE_DESC) VALUES (1, 'Assets');
INSERT INTO RESPONSIBLE_TYPE(RESPONSIBLE_TYPE_ID, RESPONSIBLE_TYPE_DESC) VALUES (2, 'Expenses');
INSERT INTO RESPONSIBLE_TYPE(RESPONSIBLE_TYPE_ID, RESPONSIBLE_TYPE_DESC) VALUES (3, 'Debts');
-- *************** New Table RESPONSIBLE_BY_TYPE ***************************
CREATE TABLE RESPONSIBLE_BY_TYPE
(
RESPONSIBLE_ID NUMBER(10) NOT NULL,
RESPONSIBLE_EXPENSES_ID NUMBER(10) NOT NULL,
RESPONSIBLE_ASSETS_ID NUMBER(10) NOT NULL,
RESPONSIBLE_DEBTS_ID NUMBER(10) NOT NULL,
RESPONSIBLE_DESC VARCHAR(100),
RESPONSIBLE_TYPE_ID NUMBER(10),
-- NOTE *** FK Constraints References PKs in referenced tables *** ----------
CONSTRAINT fk_resp_by_type_resp
FOREIGN KEY(RESPONSIBLE_ID) REFERENCES RESPONSIBLE(RESPONSIBLE_ID),
CONSTRAINT fk_resp_by_type_idnt
FOREIGN KEY(RESPONSIBLE_EXPENSES_ID, RESPONSIBLE_ASSETS_ID, RESPONSIBLE_DEBTS_ID)
REFERENCES IDENT(RESPONSIBLE_EXPENSES_ID, RESPONSIBLE_ASSETS_ID, RESPONSIBLE_DEBTS_ID),
CONSTRAINT fk_resp_by_type_resptype
FOREIGN KEY(RESPONSIBLE_TYPE_ID) REFERENCES RESPONSIBLE_TYPE(RESPONSIBLE_TYPE_ID)
-- option 2 -- FK(RESPONSIBLE_TYPE_ID, RESPONSIBLE_TYPE_DESC) references RESPONSIBLE_TYPE(RESPONSIBLE_TYPE_ID, RESPONSIBLE_TYPE_DESC)
);
-- R e s u l t
table RESPONSIBLE created.
table RESPONSIBLE altered.
table RESPONSIBLE altered.
1 rows inserted.
1 rows inserted.
table IDENT created.
table IDENT altered.
table RESPONSIBLE_TYPE created.
1 rows inserted.
1 rows inserted.
1 rows inserted.
table RESPONSIBLE_BY_TYPE created

Many-to-Many Link Table Foreign Key Modeling in SQLite

I have the following two tables in SQLite:
CREATE TABLE `Link` (
`link_id` integer NOT NULL,
`part_id` integer NOT NULL,
CONSTRAINT `link_pk` PRIMARY KEY(`link_id`,`part_id`)
);
CREATE TABLE `Main` (
`main_id` integer NOT NULL PRIMARY KEY AUTOINCREMENT,
`link_id` integer NOT NULL REFERENCES `Link`(`link_id`)
);
INSERT INTO `Link` (link_id, part_id) VALUES (1,10);
INSERT INTO `Link` (link_id, part_id) VALUES (1,11);
INSERT INTO `Link` (link_id, part_id) VALUES (1,12);
INSERT INTO `Link` (link_id, part_id) VALUES (2,15);
INSERT INTO `Main` (main_id, link_id) VALUES (1,1);
INSERT INTO `Main` (main_id, link_id) VALUES (2,1);
INSERT INTO `Main` (main_id, link_id) VALUES (3,2);
Many Main rows may reference the same link id, and many Link rows may have the same link id, such that select * from Main natural join Link where main_id=1 will return N rows, and select * from Main where link_id=1 will return K rows. The link id is important, and the original data each main has 1 link id, and each link has N part ids.
Using the schemas above, I am unable to insert any rows in Main due to the foreign key constraint (foreign key mismatch - "Main" referencing "Link": INSERT INTO Main (main_id, link_id) VALUES (1,1);), presumably because of the composite key requirement. I can get this to work by removing the foreign key constraint, but then I am obviously missing a constraint. Reversing the direction of the key wouldn't work either since, as stated above, it's a Many-to-Many relationship. Is there a way to properly model this in SQLite with a constraint that at least one row exists in Link for each link_id in Main?
I would propose a different design.
Each of the 2 entities link_id and part_id should be the primary key in 2 tables, something like:
CREATE TABLE Links (
link_id INTEGER PRIMARY KEY,
link_description TEXT
);
CREATE TABLE Parts (
part_id INTEGER PRIMARY KEY,
part_description TEXT
);
Then, create the junction table of the above tables (like your current Link table):
CREATE TABLE Links_Parts (
link_id INTEGER NOT NULL REFERENCES Links(link_id),
part_id INTEGER NOT NULL REFERENCES Parts(part_id),
PRIMARY KEY(link_id, part_id)
);
and the table Main:
CREATE TABLE Main (
main_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
link_id INTEGER NOT NULL REFERENCES Links(link_id)
);
All the relations are there and you have referential integrity guaranteed if you set foreign key support:
PRAGMA foreign_keys = ON;
See a simplified demo.

PostgreSQL check constraint for foreign key condition

I have a table of users eg:
create table "user" (
id serial primary key,
name text not null,
superuser boolean not null default false
);
and a table with jobs:
create table job (
id serial primary key,
description text
);
the jobs can be assigned to users, but only for superusers. other users cannot have jobs assigned.
So I have a table whereby I see which job was assigned to which user:
create table user_has_job (
user_id integer references "user"(id),
job_id integer references job(id),
constraint user_has_job_pk PRIMARY KEY (user_id, job_id)
);
But I want to create a check constraint that the user_id references a user that has user.superuser = True.
Is that possible? Or is there another solution?
This would work for INSERTS:
create or replace function is_superuser(int) returns boolean as $$
select exists (
select 1
from "user"
where id = $1
and superuser = true
);
$$ language sql;
And then a check contraint on the user_has_job table:
create table user_has_job (
user_id integer references "user"(id),
job_id integer references job(id),
constraint user_has_job_pk PRIMARY KEY (user_id, job_id),
constraint chk_is_superuser check (is_superuser(user_id))
);
Works for inserts:
postgres=# insert into "user" (name,superuser) values ('name1',false);
INSERT 0 1
postgres=# insert into "user" (name,superuser) values ('name2',true);
INSERT 0 1
postgres=# insert into job (description) values ('test');
INSERT 0 1
postgres=# insert into user_has_job (user_id,job_id) values (1,1);
ERROR: new row for relation "user_has_job" violates check constraint "chk_is_superuser"
DETAIL: Failing row contains (1, 1).
postgres=# insert into user_has_job (user_id,job_id) values (2,1);
INSERT 0 1
However this is possible:
postgres=# update "user" set superuser=false;
UPDATE 2
So if you allow updating users you need to create an update trigger on the users table to prevent that if the user has jobs.
The only way I can think of is to add a unique constraint on (id, superuser) to the users table and reference that from the user_has_job table by "duplicating" the superuser flag there:
create table users (
id serial primary key,
name text not null,
superuser boolean not null default false
);
-- as id is already unique there is no harm adding this additional
-- unique constraint (from a business perspective)
alter table users add constraint uc_users unique (id, superuser);
create table job (
id serial primary key,
description text
);
create table user_has_job (
user_id integer references users (id),
-- we need a column in order to be able to reference the unique constraint in users
-- the check constraint ensures we only reference superuser
superuser boolean not null default true check (superuser),
job_id integer references job(id),
constraint user_has_job_pk PRIMARY KEY (user_id, job_id),
foreign key (user_id, superuser) references users (id, superuser)
);
insert into users
(id, name, superuser)
values
(1, 'arthur', false),
(2, 'ford', true);
insert into job
(id, description)
values
(1, 'foo'),
(2, 'bar');
Due to the default value, you don't have to specify the superuser column when inserting into the user_has_job table. So the following insert works:
insert into user_has_job
(user_id, job_id)
values
(2, 1);
But trying to insert arthur into the table fails:
insert into user_has_job
(user_id, job_id)
values
(1, 1);
This also prevents turning ford into a non-superuser. The following update:
update users
set superuser = false
where id = 2;
fails with the error
ERROR: update or delete on table "users" violates foreign key constraint "user_has_job_user_id_fkey1" on table "user_has_job"
Detail: Key (id, superuser)=(2, t) is still referenced from table "user_has_job".
Create a separate superuser table that inherits from the user table:
CREATE TABLE "user" (
id serial PRIMARY KEY,
name text NOT NULL,
);
CREATE TABLE superuser () INHERITS ("user");
The user_has_job table can then reference the superuser table:
CREATE TABLE user_has_job (
user_id integer REFERENCES superuser (id),
job_id integer REFERENCES job(id),
PRIMARY KEY (user_id, job_id)
);
Move users around between the tables as needed by inserting and deleting:
WITH promoted_user AS (
DELETE FROM "user" WHERE id = 1 RETURNING *
) INSERT INTO superuser (id, name) SELECT id, name FROM promoted_user;
I don't know if this is a good way to do it but it seems to work
INSERT INTO user_has_job (user_id, job_id) VALUES (you_user_id, your_job_id)
WHERE EXIST (
SELECT * FROM user WHERE id=your_user_id AND superuser=true
);

Oracle SQL, trigger inserting row into table X as FK for currently inserted row in table Y

So in Oracle 11g I have the following:
CREATE TABLE OBJECT(
ID NUMBER(8) NOT NULL,
CATEGORY_ENUM_ID NUMBER(8) NOT NULL
);
CREATE SEQUENCE OBJECT_SEQ
START WITH 1
INCREMENT BY 1
NOCACHE
NOCYCLE;
/
CREATE TABLE TREE(
ID NUMBER(8) NOT NULL,
OBJECT_ID NUMBER(8) NOT NULL,
NAME NVARCHAR2(128)
);
CREATE TABLE CATEGORY_ENUM(
ID NUMBER(8) NOT NULL,
NAME NVARCHAR2(64)
);
-- PK's
ALTER TABLE TREE
ADD CONSTRAINT TREE_PK PRIMARY KEY (ID);
ALTER TABLE OBJECT
ADD CONSTRAINT OBJECT_PK PRIMARY KEY (ID);
ALTER TABLE CATEGORY_ENUM
ADD CONSTRAINT CATEGORY_ENUM_PK PRIMARY KEY (ID)
--- FK's
ALTER TABLE TREE
ADD CONSTRAINT TREE_OBJECT_FK FOREIGN KEY (OBJECT_ID)
REFERENCES OBJECT (ID);
ALTER TABLE OBJECT
ADD CONSTRAINT OBJECT_CATEGORY_FK FOREIGN KEY (CATEGORY_ENUM_ID)
REFERENCES CATEGORY_ENUM (ID);
-- Closed dictionary sample data
INSERT INTO CATEGORY_ENUM (ID, NAME) VALUES (1, 'TREE');
INSERT INTO CATEGORY_ENUM (ID, NAME) VALUES (2, 'HERB');
INSERT INTO CATEGORY_ENUM (ID, NAME) VALUES (3, 'SHROOM');
-- Triggers
CREATE OR REPLACE TRIGGER TREE_before_insert
BEFORE INSERT
ON TREE
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE
CATEGORY_ID NUMBER;
BEGIN
SELECT ID INTO CATEGORY_ID FROM CATEGORY_ENUM WHERE NAME = 'TREE' AND ROWNUM <= 1;
if :NEW.OBJECT_ID is null then
:NEW.OBJECT_ID := OBJECT_SEQ.nextval;
INSERT INTO OBJECT (ID, CATEGORY_ENUM_ID) VALUES (:NEW.OBJECT_ID, CATEGORY_ID);
end if;
END;
/
If next I run:
INSERT INTO TREE (ID, NAME) VALUES (1, 'Tree1');
INSERT INTO TREE (ID, NAME) VALUES (2, 'Tree2');
I get an error:
...
TRIGGER TREE_BEFORE_INSERT compiled
Error starting at line 91 in command:
INSERT INTO TREE (ID, NAME) VALUES (1, 'Tree1')
Error report:
SQL Error: ORA-02291: integrity constraint (HR.TREE_OBJECT_FK) violated - parent key not found
02291. 00000 - "integrity constraint (%s.%s) violated - parent key not found"
*Cause: A foreign key value has no matching primary key value.
*Action: Delete the foreign key or add a matching primary key.
1 rows inserted.
But if before the above, I insert anything into FEATURES table (like below), it works fine.
INSERT INTO OBJECT (ID, CATEGORY_ENUM_ID) VALUES (0, 1);
INSERT INTO TREE (ID, NAME) VALUES (1, 'Tree1');
INSERT INTO TREE (ID, NAME) VALUES (2, 'Tree2');
So the problem occurs only for the very first insert, the others work fine, IDs assigned from OBJECT_SEQ.nextval are proper.
What am I doing wrong ?
Jah bless ya for help.
EDIT I have removed some unnecessary code, so now it's more clear and shorter.
The problem here is that you have a primary key constraint placed on the "TREE" table and a foreign key constraint placed on the "OBJECT" table. So any new record that you try inserting into the table with foreign key constraint, make sure it is already available in the table that has the primary key mapping.
Example shown below:
**Tables:**
create table tab1
(id number,
name varchar2(100)
)
create table tab2
(id number,
name varchar2(100)
)
**constraints added:**
alter table tab1 add constraint pk_tab1_id primary key (id)
alter table tab2 add constraint fk_tab2_id foreign key(id) references tab1(id)
**Insert statement on the second table:**
insert into tab2(values(1,'abc')
**Error:**
SQL Error: ORA-02291: integrity constraint (PRAVE.fk_tab2_id) violated - parent key not found
02291. 00000 - "integrity constraint (%s.%s) violated - parent key not found"
*Cause: A foreign key value has no matching primary key value.
*Action: Delete the foreign key or add a matching primary key.
**Solution:**
**Insert into the table with PK first as below:**
insert into tab1 values(1,'abc')
1 rows inserted.
insert into tab2 values(1,'abc')
1 rows inserted.

Reusing a constraint while creating a table

While creating a table how can I reuse a constraint that has been mentioned for a previous column?
create table ticket_details(
from_stn char(3)
constraint chk check(from_stn in ('vsh','mas','ndl'))
constraint nn NOT NULL,
to_stn char(3)
constraint nn1 NOT NULL, (instead of crea)
seat_no number(3)
constraint PK primary key,
);
A domain constraint will be enforced on any instance of the domain. Also: upon change, you'll have to change it in only one place. (the syntax might differ slightly between implementations)
CREATE DOMAIN THE_STN CHAR(3) constraint THE_STN_check_da_value check(VALUE in ('vsh','mas','ndl'))
;
CREATE table ticket_details
( seat_no INTEGER NOT NULL PRIMARY KEY
, from_stn THE_STN NOT NULL
, to_stn THE_STN
);
INSERT INTO ticket_details(seat_no,from_stn,to_stn) VALUES (1, 'vsh', 'ndl' ); -- succeeds
INSERT INTO ticket_details(seat_no,from_stn,to_stn) VALUES (2, 'vsh', NULL ); -- succeeds
INSERT INTO ticket_details(seat_no,from_stn,to_stn) VALUES (2, 'lol', 'mas' ); -- fails
Reusing a constraint for another column is not possible. You have to define it for other column if you want