I have question with a ER diagram I'm creating for a database, I basically have 2 tables, one is called 'Employee' and the other is called 'Store'. Each store has certain number of employees, I need to know in what store the employee is located. The thing is, A store is required to have a boss/manager who has to be one of the employees. The picture below shows how I made it. However when I create these tables on PostgreSQL I get an error because I'm referencing a table who has not been created yet.
This is how I'm trying to create the two tables, how can I solve this?
Any ideas?
create table Store(
store_id serial primary key,
storeName varchar(20),
employee_id int,
foreign key (employee_id) references Employee(employee_id)
);
create table Employee(
employee_id serial primary key,
firstname varchar(50),
lastname varchar(50),
address varchar(50)
email varchar(100),
store_id int,
foreign key (store_id) references Store(store_id)
);
Error:
SQL Error [42P01]: ERROR: relation "employee" does not exist
All you would have to do is create the foreign key constraints after the tables have been created like this
create table Store(
store_id serial primary key,
storeName varchar(20),
employee_id int
);
create table Employee(
employee_id serial primary key,
firstname varchar(50),
lastname varchar(50),
address varchar(50),
email varchar(100),
store_id int
);
alter table Store add constraint fk_store_employee_id foreign key (employee_id) references Employee(employee_id) DEFERRABLE INITIALLY DEFERRED;;
alter table Employee add constraint fk_employee_store_id foreign key (store_id) references Store(store_id) DEFERRABLE INITIALLY DEFERRED;;
the DEFERRABLE INITIALLY DEFERRED makes it that the constraint is checked at the end of the transaction otherwise you would get a foreign key constraint violation since the employee wouldn't exist when you create the store and the store wouldn't exist when you create the employee.
here is a working example https://www.db-fiddle.com/f/71b3KhwDMSgKmsWsbAeUTR/1
but even with the DEFERRABLE INITIALLY DEFERRED how would you know what id an employee and store is going to get?
i think you might be better off using a third table to store store managers like this
create table Store(
store_id serial primary key,
storeName varchar(20)
);
create table Employee(
employee_id serial primary key,
firstname varchar(50),
lastname varchar(50),
address varchar(50),
email varchar(100),
store_id int,
foreign key(store_id) references Store(store_id)
);
create table StoreManager (
store_id int,
employee_id int,
primary key(store_id, employee_id),
foreign key(store_id) references Store(store_id),
foreign key(employee_id) references Employee(employee_id)
);
this you can first create the store then the employee and then you can pair the two in the StoreManager table
here is a working example https://www.db-fiddle.com/f/71b3KhwDMSgKmsWsbAeUTR/2
Related
I'm very new to database designing and I'm creating a small project to understand it better, I'm trying to come up with a new school crm. I started with the below schema:
create table student(
id int not null,
firstname varchar(100),
lastname varchar(100),
PRIMARY key (id)
);
create table address(
id int not null,
street varchar(30) not null,
city varchar(30) not null,
PRIMARY KEY (id)
);
-- they have own roles for app
create table guardians(
id int not null,
firstname varchar(100),
lastname varchar(100),
primary key (id)
);
-- teacher have own roles
create table teacher(
id int not null,
firstname varchar(100),
lastname varchar(100),
PRIMARY key (id)
)
guardians and teachers will have password for login the web portal. The reason why I created separate table is mainly because teachers might have column's like salary, schoolId etc in the future. But now if I look at the schema here, mostly the firstName, lastname is common for all student, teacher and guardians.
How can I have a common table for such repeatable field names? Or this design is good? Also I wanted to have another table ROLE which going to give permissions at app level to update/insert certain tables. Not sure how can I design it as well.
The schema you have planned will end up having and lot of redundancies in different tables (like firstName and lastName as you have described for each of the three tables). Also, if in future a new role turns up you will be creating new table and leading to more redundancy.
I would suggest it would we better if you create one table for user and define role of the user in that table.
e.g.:
create table user(
u_id int not null,
firstname varchar(100),
lastname varchar(100),
role varchar(100),
PRIMARY key (id)
);
You can maintain role specific data in different table and can be accessed via primary key of user table.
e.g.:
create table teacher(
t_id int not null,
u_id int,
Salary int,
qualification varchar(100),
PRIMARY key (id),
FOREIGN KEY (u_id) REFERENCES user(u_id)
)
Having a role column in user table will solve your second problem as well.
I have two tables, below are the strutures
CREATE TABLE IF NOT EXISTS nl_address (
id int NOT NULL GENERATED BY DEFAULT AS IDENTITY,
address_text varchar(100),
pincode varchar(6),
city_id int NOT NULL,
state_id int NOT NULL,
country_id int NOT null,
is_active boolean default true,
PRIMARY KEY (id),
CONSTRAINT fk_city_id FOREIGN KEY(city_id) REFERENCES nl_city(id),
CONSTRAINT fk_state_id FOREIGN KEY(state_id) REFERENCES nl_state(id),
CONSTRAINT fk_country_id FOREIGN KEY(country_id) REFERENCES nl_country(id)
);
CREATE TABLE IF NOT EXISTS nl_customer (
cust_id int NOT NULL,
prefix varchar(10) default 'CUST-',
suffix varchar(2),
org_name varchar(100) NOT NULL,
domain_name varchar(100) NOT NULL,
pan_number varchar(10) NOT null,
pri_contact varchar(10) NOT NULL,
pri_number varchar(10) NOT NULL,
pri_email varchar(30) NOT NULL,
sec_contact varchar(10),
sec_number varchar(10),
sec_email varchar(30),
is_active boolean default true,
addr_id int not null,
created_date date,
created_by varchar(10),
updated_date date,
updated_by varchar(10),
PRIMARY KEY (cust_id),
CONSTRAINT fk_address_id FOREIGN KEY(addr_id) REFERENCES nl_address(id)
);
The problem is, neither I am able to update or delete
If i am trying to update record in nl_address, I got an violation error that the field is used inside `nl_customer.
If i tried to update from nl_customer, then I got an violation error that the field is used inside nl_address
It was originated, when JPA trying to persist the data, I have inserted a dummy data with id 1, when JPA trying to insert another record then it throws
.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "nl_address_pkey"
Detail: Key (id)=(1) already exists.
It seems there is something wrong with the table structure, any help appreciated
Actually this is common that you cannot update or delete that belong to primary/foreign key if you generate duplicates, as all values should be unique (i.e. if you have already id=1 and update id=2 to id=1, you will get the error you mentioned) and because a foreign key construct is a specific relationship it should be clarified what will happen with this relationship.
In case of 'nl_address' you used 'GENERATED BY DEFAULT AS IDENTITY' which have the same purpose as SERIAL (i.e. auto increment), but it is more compliant with SQL standard. (I assume you are also aware of difference between GENERATED BY DEFAULT and GENERATED ALWAYS)
However, you can specify the sequence in order to ensure the proper auto increment functionality.
ALTER TABLE nl_address
ALTER COLUMN "id"
DROP IDENTITY IF EXISTS;
ALTER TABLE nl_address
ALTER COLUMN "id"
ADD GENERATED BY DEFAULT AS IDENTITY (START WITH 1 INCREMENT 1);
If you use UPDATE or DELETE on FOREIGN KEY construct ensure what should happen with relationship:
[CONSTRAINT fk_name]
FOREIGN KEY(fk_columns)
REFERENCES parent_table(parent_key_columns)
[ON DELETE delete_action]
[ON UPDATE update_action]
/* as delete_action or update_action you can use e.g. SET NULL, RESTRICT or CASCADE;
so ensure what happen with records in related table*/
Is there a way to create both tables while being a foreign key of one another? I am using SQL Server Management Studio
--DROP TABLE orders
CREATE TABLE orders
(
orderId bigint PRIMARY KEY IDENTITY(880001, 1) NOT NULL,
receiptNo bigint FOREIGN KEY REFERENCES receipt(receiptId),
productId bigint FOREIGN KEY REFERENCES productServices(productId),
quantity int,
dateOrdered datetime DEFAULT CURRENT_TIMESTAMP
)
--DROP TABLE receipt
CREATE TABLE receipt
(
receiptNo bigint PRIMARY KEY IDENTITY(900001, 1) NOT NULL,
employeeId bigint FOREIGN KEY REFERENCES employeeInfo(employeeId),
customerId bigint FOREIGN KEY REFERENCES customerInfo(customerId),
orderId bigint FOREIGN KEY REFERENCES orders(orderId),
paymentMethod varchar(4),
dateOfPurchase datetime DEFAULT CURRENT_TIMESTAMP
)
The requirement always is: a table must exist before you can create a foreign key reference to it. So in your case, obviously, you cannot create both table with the full FK references in place, since they reference each other.
What you need to do is:
CREATE TABLE orders without the FK reference to Receipt (since that table doesn't exist yet at this time)
CREATE TABLE receipt - here you can include the FK reference to orders - that table has been created and exists
Alter your table orders to add the FK reference to receipt:
ALTER TABLE dbo.orders
ADD CONSTRAINT FK_Orders_Receipt
FOREIGN KEY (receiptNo) REFERENCES dbo.receipt(receiptId);
Of course, the same applies to all the other FK constraints you have - you cannot reference a table that doesn't exist yet. You must first create the tables, then you can add the FK constraints.
For you Case, you change the order of creating the Table.
1.) Before adding a Foreign Key References to a new table, the table to be refereed as a foreign key must be already exists.
2.) Also a add a batch Separator GO statement while single Execution of creating tables.
--DROP TABLE receipt
CREATE TABLE receipt
(
receiptNo bigint PRIMARY KEY IDENTITY(900001, 1) NOT NULL,
employeeId bigint FOREIGN KEY REFERENCES employeeInfo(employeeId),
customerId bigint FOREIGN KEY REFERENCES customerInfo(customerId),
orderId bigint FOREIGN KEY REFERENCES orders(orderId),
paymentMethod varchar(4),
dateOfPurchase datetime DEFAULT CURRENT_TIMESTAMP
)
GO
--DROP TABLE orders
CREATE TABLE orders
(
orderId bigint PRIMARY KEY IDENTITY(880001, 1) NOT NULL,
receiptNo bigint FOREIGN KEY REFERENCES receipt(receiptId),
productId bigint FOREIGN KEY REFERENCES productServices(productId),
quantity int,
dateOrdered datetime DEFAULT CURRENT_TIMESTAMP
)
GO
This is hard because it's wrong. There's no need for two FKs and they are actively harmful as you could have an order whose receipt points to a different order. The right design here is to just have one FK, and enforce uniqueness on the FK column. Thus an order may be created first, and later at most one receipt can be added for that order.
eg:
create table employeeInfo(employeeid bigint primary key)
create table customerInfo(customerID bigint primary key)
create table productServices(productId bigint primary key)
CREATE TABLE orders
(
orderId bigint PRIMARY KEY IDENTITY(880001, 1) NOT NULL,
--receiptNo bigint FOREIGN KEY REFERENCES receipt(receiptId),
productId bigint FOREIGN KEY REFERENCES productServices(productId),
quantity int,
dateOrdered datetime DEFAULT CURRENT_TIMESTAMP
)
CREATE TABLE receipt
(
receiptNo bigint PRIMARY KEY IDENTITY(900001, 1) NOT NULL,
employeeId bigint FOREIGN KEY REFERENCES employeeInfo(employeeId),
customerId bigint FOREIGN KEY REFERENCES customerInfo(customerId),
orderId bigint FOREIGN KEY REFERENCES orders(orderId) unique,
paymentMethod varchar(4),
dateOfPurchase datetime DEFAULT CURRENT_TIMESTAMP
)
I have one teacher_details table that has teacher_id as the primary key and one exam_details table which has exam_id as one attribute.
I want one teacher can't create the same exam_id more than one time but it can be possible that 2 teachers can create the same exam_id.
Should I make exam_id as the primary key or I will check that in the servlet?
I am using sql-server for database.
create table teacher_details(
teacher_id varchar(20) not null primary key,
teacher_name varchar(30));
create table exam_details(exam_id varchar(20), exam_name varchar(30), teacher_id varchar(20), foreign key (teacher_id) references teachers_details(teacher_id));
You should make the combination of exame_id and teacher_id the primary key of your exam_details table.
Also, you should get used to naming your constraints:
create table teacher_details
(
teacher_id varchar(20) not null,
teacher_name varchar(30),
constraint pk_teacher_details primary key (teacher_id)
);
create table exam_details (
exam_id varchar(20),
exam_name varchar(30),
teacher_id varchar(20),
constraint fk_teacher_exam foreign key (teacher_id) references teacher_details(teacher_id),
constraint pk_exam_details primary key (teacher_id, exam_id)
);
You should check this in servlet, because if you make exam_id as primary key, than two teachers would not be able to create the same exam_id
Below is the CREATE script for all those tables
Table schools schema
CREATE TABLE schools
(
NAME VARCHAR(20),
levell VARCHAR(20),
adress VARCHAR(20),
main_language VARCHAR(20),
email VARCHAR(20),
information VARCHAR(80),
mission VARCHAR(80),
vision VARCHAR(80),
type VARCHAR(20),
fees REAL,
phone_number INT,
PRIMARY KEY (NAME, levell)
)
Table school_phones schema
CREATE TABLE school_phones
(
NAME VARCHAR(20) PRIMARY KEY,
phone_number INT,
FOREIGN KEY (NAME, phone_number) REFERENCES schools
)
--phone.name references school
Table elementary_schools schema
CREATE TABLE elementary_schools
(
NAME VARCHAR(20) FOREIGN KEY REFERENCES schools(NAME) ,
levell VARCHAR(20) FOREIGN KEY REFERENCES schools(levell) ,
PRIMARY KEY(NAME , levell)
)
--elementary.name references school
Table elementary_school_supplies schema
CREATE TABLE elementary_school_supplies
(
NAME VARCHAR(20) PRIMARY KEY FOREIGN KEY REFERENCES elementary_schools(
NAME),
supplies VARCHAR(20)
)
--Elementary_Schools.name references elementary
Table middle_schools schema
CREATE TABLE middle_schools
(
NAME VARCHAR(20) PRIMARY KEY FOREIGN KEY REFERENCES schools
)
--middle.name references school
Table high_schools schema
CREATE TABLE high_schools
(
NAME VARCHAR(20) PRIMARY KEY FOREIGN KEY REFERENCES schools
)
The errors are displayed in the below pictures
Error1:
Error2:
Any help to solve this would be appreciated. Thanks in Advance.
Your first issue is that your PK on Schools is a composite of name and levell. You're trying to reference these with separate FK's, you need a composite FK too.
You want to do the same thing that you've done with the School_Phones table, something like this;
CREATE TABLE Elementary_Schools (name varchar(20), levell varchar(20), primary key (name, levell), foreign key (name, levell) references Schools)
The second issue is pretty self explanatory, you can only FK fields of the same data type. Your phone_number field (int) cannot reference levell as it's a varchar(20). These need to both be the same data type.