How to enforce a unique constraint across multiple tables? - sql

I have created the following two tables to map out students and teachers :
CREATE TABLE students(
student_id SERIAL PRIMARY KEY,
first_name NOT NULL VARCHAR(50),
last_name NOT NULL VARCHAR(50),
phone VARCHAR(15) UNIQUE NOT NULL CHECK (phone NOT LIKE '%[^0-9]%'),
email VARCHAR(30) UNIQUE NOT NULL CHECK (email NOT LIKE '%#%'),
graduationYear SMALLINT CHECK (graduationYear > 1900)
);
CREATE TABLE teachers(
teacher_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
departament VARCHAR(40) NOT NULL,
email VARCHAR(30) UNIQUE NOT NULL CHECK (email NOT LIKE '%#%'),
phone VARCHAR(15) UNIQUE NOT NULL CHECK (phone NOT LIKE '%[^0-9]%')
);
As you can see, both tables have a column for phone and email. I want these two to be unique to each individual.
How can I introduce a constraint that will check if the phone number/email introduced, for example, in the students table doesn't already exist in the teachers table?
Is there any kind of keyword that works like UNIQUE but on multiple tables or should I take another approach?
Edit: as #a_horse_with_no_name pointed out, LIKE doesn't support regular expressions. I should have used SIMILAR TO.

I would create a single table person that contains all attributes that are common to both including a type column that identifies teachers and students. Then you can create unique constraints (or indexes) on the phone and email columns.
To store the "type specific" attributes (graduation year, department) you can either have nullable columns in the person table and only put in values depending on the type. If you do not expect to have more "type specific" attributes apart from those two, this is probably the easiest solution
If you expect more "type specific" attributes, additional tables (student and teacher) with containing those can also be used. This is the traditional way of modelling inheritance in a relational database. As Postgres supports table inheritance, you could also create the teacher and student tables to inherit from the person table.

Related

How do I realize this 3 simple things in SQL?

i am an absolute SQL beginner and i already did search a lot with google but didnt find what i needed. So how do i realize in SQL(translated from a ER-Model):
An Entity having an Atribute that can have mulitple Entrys(I already found the ARRAY contstraint but i am unsure about that)
An Entity having an Atribute that consists itself of a few more Atributes(Picture: http://static3.creately.com/blog/wp-content/uploads/2012/03/Attributes-ER-Diagrams.jpeg)
Something like a isA Relation. And especially the total/partial and the disjunct characteristics.
Thanks already
In Postgres you have all three of this:
create table one
(
id integer primary key,
tags text[] -- can store multiple tags in a single column
);
A single column with multiple attributes can be done through a record type:
create type address as (number integer, street varchar(100), city varchar(100));
create table customer
(
id integer primary key,
name varchar(100) not null,
billing_address address
);
An isA relation can be done using inheritance
create table paying_customer
(
paid_at timestamp not null,
paid_amount decimal(14,2) not null
)
inherits (customer);
A paying customer has all attributes of a customer plus the time when the invoice was paid.

Database table design for college management system

I'm a lion beginner. I'm developing a database for College Management System. For that I decided to create tables. First basically I designed two tables..
They are Student and Department.
create table dept_pro
(
dept_id numeric(1) primary key,
name char(20),
hod nvarchar(25),
location nvarchar(10)
);
create table student_pro
(
rollno char(10) primary key,
name nvarchar(25) not null,
dept_id numeric(1) not null foreign key references dbo.dept_pro(dept_id),
ac_year numeric(1) not null check( ac_year in (1,2,3,4)),
sem numeric(1) not null check ( sem in (1,2)),
mobile nvarchar(13),
addr nvarchar not null
);
I established a relation between them using a Foreign Key. Now I need to add another set of tables, one for attendance and the other for maintaining marks. There will be maximum of 6 subjects in a semester, and after each semester the subjects change. As the subjects change the corresponding subjects in the attendance table should also change. How can I change the subjects in the marks and attendance table after each semester? And also another important issue is each subject has 3 exams. I tried to create a user-defined type for this each subject having 3 columns exam1,exam2 and exam3(In oracle we create user defined type as a combination of one or more columns).
I'm now using SQL Server. SQL Server is not supporting user-defined datatypes as in Oracle like CREATE DATA..... AS OBJECT.This is further increasing complexity of marks table.
Now how can I solve above problem of maintaining marks & attendance table keeping in mind that the subjects change after each semester. Help me I'm a beginner.
Thanks in advance!!

Implementing complex references without a trigger in PostgreSQL

I am creating a PostgreSQL database: Country - Province - City.
A city must belong to a country and can belong to a province.
A province must belong to a country.
A city can be capital of a country:
CREATE TABLE country (
id serial NOT NULL PRIMARY KEY,
name varchar(100) NOT NULL
);
CREATE TABLE province (
id serial NOT NULL PRIMARY KEY,
name varchar(100) NOT NULL,
country_id integer NOT NULL,
CONSTRAINT fk_province_country FOREIGN KEY (country_id) REFERENCES country(id)
);
CREATE TABLE city (
id serial NOT NULL PRIMARY KEY,
name varchar(100) NOT NULL,
province_id integer,
country_id integer,
CONSTRAINT ck_city_provinceid_xor_countryid
CHECK ((province_id is null and country_id is not null) or
(province_id is not null and country_id is null)),
CONSTRAINT fk_city_province FOREIGN KEY (province_id) REFERENCES province(id),
CONSTRAINT fk_city_country FOREIGN KEY (country_id) REFERENCES country(id)
);
CREATE TABLE public.capital (
country_id integer NOT NULL,
city_id integer NOT NULL,
CONSTRAINT pk_capital PRIMARY KEY (country_id, city_id),
CONSTRAINT fk_capital_country FOREIGN KEY (country_id) REFERENCES country(id),
CONSTRAINT fk_capital_city FOREIGN KEY (city_id) REFERENCES city(id)
);
For some (but not all) countries I will have province data, so a city will belong to a province, and the province to a country. For the rest, I shall just know that the city belongs to a country.
Issue #1: Concerning the countries that I do have province data, I was looking for a solution that will disallow a city to belong to a country and at the same time to a province of a different country.
I preferred to enforce through a check constraint that either province or country (but NOT both) are not null in city. Looks like a neat solution.
The alternative would be to keep both province and country info within the city and enforce consistency through a trigger.
Issue #2: I want to disallow that a city is a capital to a country to which it does not belong. That seems impossible without a trigger after my solution to issue #1 because there is no way to directly reference the country a city belongs to.
Maybe the alternative solution to issue #1 is better, it also simplifies future querying.
I would radically simplify your design:
CREATE TABLE country (
country_id serial PRIMARY KEY -- pk is not null automatically
,country text NOT NULL -- just use text
,capital int REFERENCES city -- simplified
);
CREATE TABLE province ( -- never use "id" as name
province_id serial PRIMARY KEY
,province text NOT NULL -- never use "name" as name
,country_id integer NOT NULL REFERENCES country -- references pk per default
);
CREATE TABLE city (
city_id serial PRIMARY KEY
,city text NOT NULL
,province_id integer NOT NULL REFERENCES province,
);
Since a country can only have one capitol, no n:m table is needed.
Never use "name" or "id" as column names. That's an anti-pattern of some ORMs. Once you join a couple of tables (which you do a lot in relational databases) you end up with multiple columns of the same non-descriptive name, causing all kinds of problems.
Just use text. No point in varchar(n). Avoid problem like this.
The PRIMARY KEY clause makes a column NOT NULL automatically. (NOT NULL sticks, even if you later remove the pk constraint.)
And most importantly:
A city only references one province in all cases. No direct reference to country. Therefore mismatches are impossible, on-disk storage is smaller and your whole design is much simpler. Queries are simpler.
For every country enter a single dummy-province with an empty string as name (''), representing the country "as a whole". (Possibly even with the same id, you could have provinces and countries draw from the same sequence ...). Do this automatically in a trigger. This trigger is optional, though.
I chose an empty string instead of NULL, so the column can still be NOT NULL and a unique index over (country_id, province) does its job. You can easily identify this province representing the whole country and deal with it as appropriate in your application.
I am using a similar design successfully in multiple instances.
I think you can actually implement all these constraints without using triggers. It does require a bit of restructuring of the data.
Start by enforcing the relationship (using foreign keys) of:
city --> province --> country
For countries with no province information, invent a province -- perhaps with the country name, perhaps some weird default name ("CountryProvince"). This allows you to have only one set of relationship between the three entities. It automatically ensures that cities and provinces are in the right country, because you would get the country through the province.
The final question is about capitals. There is a way that you can implement and enforce uniqueness with no triggers. Keep a flag in the cities table and use a unique filtered index to guarantee uniqueness:
create unique index on cities_capitalflag on cities(capitalflag) where capitalflag = 'Y';
EDIT:
You are right about the the filtered index needing the country. But that requires storing the country in that table, which, in turn, requires keeping the provinces and cities aligned with respect to country. So, this solution gets close to not needing triggers but it isn't there.

How to design relation between tables employee,client and phone Number?

I have a relational database with a Client table, containing id, name, and address, with many phone numbers
and I have an Employee table, also containing id, name, address, etc., and also with many phone numbers.
Is it more logical to create one "Phone Number" table and link the Clients and Employees, or to create two separate "Phone Number" tables, one for Clients and one for Employees?
If I choose to create one table, can I use one foreign key for both the Client and Employee or do I have to make two foreign keys?
If I choose to make one foreign key, will I have to make the Client ids start at 1 and increment by 5, and Employee ids start at 2 and increment by 5 so the two ids will not be the same?
If I create two foreign keys will one have a value and the other allow nulls?
The solution which I would go with would be:
CREATE TABLE Employees (
employee_id INT NOT NULL,
first_name VARCHAR(30) NOT NULL,
...
CONSTRAINT PK_Employees PRIMARY KEY (employee_id)
)
CREATE TABLE Customers (
customer_id INT NOT NULL,
customer_name VARCHAR(50) NOT NULL,
...
CONSTRAINT PK_Customers PRIMARY KEY (customer_id)
)
-- This is basic, only supports U.S. numbers, and would need to be changed to
-- support international phone numbers
CREATE TABLE Phone_Numbers (
phone_number_id INT NOT NULL,
area_code CHAR(3) NOT NULL,
prefix CHAR(3) NOT NULL,
line_number CHAR(4) NOT NULL,
extension VARCHAR(10) NULL,
CONSTRAINT PK_Phone_Numbers PRIMARY KEY (phone_number_id),
CONSTRAINT UI_Phone_Numbers UNIQUE (area_code, prefix, line_number, extension)
)
CREATE TABLE Employee_Phone_Numbers (
employee_id INT NOT NULL,
phone_number_id INT NOT NULL,
CONSTRAINT PK_Employee_Phone_Numbers PRIMARY KEY (employee_id, phone_number_id)
)
CREATE TABLE Customer_Phone_Numbers (
customer_id INT NOT NULL,
phone_number_id INT NOT NULL,
CONSTRAINT PK_Customer_Phone_Numbers PRIMARY KEY (customer_id, phone_number_id)
)
Of course, the model might changed based on a lot of different things. Can an employee also be a customer? If two employees share a phone number how will you handle it on the front end when the phone number for one employee is changed? Will it change the number for the other employee as well? Warn the user and ask what they want to do?
Those last few questions don't necessarily affect how the data is ultimately modeled, but will certainly affect how the front-end is coded and what kind of stored procedures you might need to support it.
"The Right Way", allowing you to use foreign keys for everything, would be to have a fourth table phoneNumberOwner(id) and have fields client.phoneNumberOwnerId and employee.phoneNumberOwnerId; thus, each client and each employee has its own record in the phoneNumberOwner table. Then, your phoneNumbers table becomes (phoneNumberOwnerId, phoneNumber), allowing you to attach multiple phone numbers to each phoneNumberOwner record.
Maybe you can somehow justify it, but to my way of thinking it is not logical to have employees and clients in the same table. It seems you wan to do this only so that your foreign keys (in the telephone-number table) all point to the same table. This is not a good reason for combining employees and clients.
Use three tables: employees, clients, and telephone-number. In the telephone table, you can have a field that indicates employee or client. As an aside, I don't see why telephone number needs to be a foreign key: that only adds complexity with very little benefit, imo.
Unless there are special business requirements I would expect a telephone number to be an attribute of an employee or client entity and not an entity in its own right.
If it were considered an entity in its own right it would be 'all key' i.e. its identifier is the compound of its attributes and has no attributes other than its identifier. If the sub-attributes aren't stored apart then it only has one attribute i.e. the telephone number itself! Therefore, it isn't usually 'interesting' enough to be an entity in its own right and a telephone numbers table, whether superclass or subclass, is usually overkill (as I say, barring special business requirements).

SQL database design for storing different types of "Person"

I need to create a table in a relational database using SQL for persons having the columns Name, LastName and so on.
I'll have three different kinds of People: Seller, Buyer and Customer.
Every person has other information/attributes.
Do I need to create a table for each different type of Person or can a single table be used for all three types?
If I used a single table, what if one type of "Person", say Seller, has different attributes from another Person type?
I would create one table Person , with personId as primary key that will contain common properties for all types.(Seller , Buyer , Customer)
Then I would create PersonTypes, a small reference table , that will declare codes for the different types .
Then for each type I would create a separate table with reference to Person table and
PersonType table that includes all the unique properties.
You can create 1 or two tables. Of course you can create 3 tables for each user role. It depend's on what you would like to achieve. Common solution to your question is: create two tables, one for users and one for their roles (examples for mysql:
Create table `person_role` (
id int not null,
roleName varchar(255) not null,
PRIMARY KEY(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
Create table `person`(
id int not null.
name varchar(255) not null,
lastName varchar(255) not null,
role int not null,
PRIMARY KEY(`id`),
CONSTRAINT FOREIGN KEY(`role`) REFERENCES person_role(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
Can a seller ever be a buyer or a customer? If they can, put it all in the same table so that you don't have separate copies of the same data.