How to organize common columns to a single table? - database

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.

Related

How can I solve this ER diagram for a database?

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

Did I write this query correctly?

I'm given the question
My solution is
USE Finances
CREATE TABLE Account
(AccountID varchar(25) NOT NULL PRIMARY KEY,
AccountName varchar(50) NOT NULL,
AccountAddress varchar(30) NULL,
AccountCity varchar(25) NULL,
AccountState char(2) NULL,
AccountZip varchar(10) NULL,
AccountPhone varchar(14) NULL)
CREATE TABLE Transactions
(TransactionID INT NOT NULL PRIMARY KEY IDENTITY,
AccountID varchar(25) REFERENCES Account (AccountID),
TransactionDate smalldatetime NOT NULL,
TransactionAmount money NOT NULL)
CREATE TABLE Register
(RegisterID INT NOT NULL PRIMARY KEY IDENTITY,
TransactionID INT NOT NULL REFERENCES Transactions (TransactionID));
Part of the reason I'm confused is because I don't completely understand the primary/foreign key relationship. Like I look at the question and say, ok the registerID will be the single/unique ID to seperate every account from each other. But I see that there's a TranasctionID in the same table. And that TransactionID is a foreign key to the TransactionID in the transaction table. So does that mean whenever a new tranasctionID is added there is a corresponding RegisterID. Like whats the point of the Register ID?? And did I write this query correctly?
The only issue in you script is your column "AccountID" in table "Transactions" is creating with allowing NULL and "TransactionAmount" is NOT NULL where as it should allow NULL. Other wise I found the tables are creating with appropriate type and relation as instructed.
Regarding your confusion, I am confused too thinking about the purpose of table "Register". As per instruction, yes it will create a new row every time a new transaction take place. As registerId is a PK, with each transaction a new PK will generate. But the question is why a new RegisterId is required for each TransactionID? If RegisterId is referring to other table for a transaction details, it can be easily use the TransactionID directly as both TransactionID and RegisterId are unique (PK).

relationship between tables hsqldb

I need to create two tables in relationship one to many. I have created following statements. Maven gives me an error about "unique constraint". I don't know how to fix it, someone can explain me how to create correct relationship in this example?
CREATE TABLE Owner(
owner_id INT GENERATED BY DEFAULT AS IDENTITY,
firstname varchar(20),
lastname varchar(20)
)
"CREATE TABLE Picture(
picture_id INT GENERATED BY DEFAULT AS IDENTITY,
owner_id INT, name varchar(20),
width INT, height INT,
FOREIGN KEY(pic_owner_id) REFERENCES Owner(owner_id)
)
You need to add a primary key.
CREATE TABLE Owner(
owner_id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
firstname varchar(20),
lastname varchar(20)
)

Create a many to many relation and give each relation an object

I am writing a query to create a database in SQL server 2008 R2. I plan to use it with entity framework in a mvc3 application
I have users, games and highscores.
What I want ot do is this:
I want to create a many-to-many relationship between users and games.
Each User can have multiple games and each game can have multiple users.
and each relation user-game has 1 high score.
So far I created the users, games, highscores tables:
CREATE TABLE Users
(
UserId INT IDENTITY(1,1),
FirstName VARCHAR(64) NOT NULL,
LastName VARCHAR(64) NOT NULL,
Email VARCHAR(200) NOT NULL,
CreatedDate DateTime NULL,
PhoneNumber VARCHAR(32) NULL,
Password VARCHAR(64),
CONSTRAINT pk_users_userid PRIMARY KEY(UserId)
)
CREATE TABLE Games
(
GameId INT IDENTITY(1,1),
Url VARCHAR(64) NOT NULL,
CONSTRAINT pk_gamess_gameid PRIMARY KEY(GameId)
)
CREATE TABLE Highscores
(
HighscoreId INT IDENTITY(1,1),
Value INT NOT NULL,
CONSTRAINT pk_surveyors_surveyorid PRIMARY KEY(HighscoreId)
)
What is the best way to create the many-to-many user-game relation and give each relation one high score? should I create a 4th table to hold the relation? And if I do so will I be able to use the database with Entity framework in an MVC3 application or would that complicate it?
Thank you
Additional note: I am planning to use this database with entity framework in a MVC 3 web application.
CREATE TABLE Users (
UserId INT IDENTITY(1,1),
FirstName VARCHAR(64) NOT NULL,
LastName VARCHAR(64) NOT NULL,
Email VARCHAR(200) NOT NULL,
CreatedDate DateTime NULL,
PhoneNumber VARCHAR(32) NULL,
Password VARCHAR(64),
CONSTRAINT pk_users_userid PRIMARY KEY(UserId)
)
CREATE TABLE Games (
GameId INT IDENTITY(1,1),
Url VARCHAR(64) NOT NULL,
CONSTRAINT pk_gamess_gameid PRIMARY KEY(GameId)
)
CREATE TABLE Highscores (
HighscoreId INT IDENTITY(1,1),
UserID Int,
GameID Int,
Value INT NOT NULL,
CONSTRAINT pk_surveyors_surveyorid PRIMARY KEY(HighscoreId)
)
ALTER TABLE [dbo].[Highscores] ADD CONSTRAINT [FK_Highscores_Games] FOREIGN KEY([GameID])
ALTER TABLE [dbo].[Highscores] ADD CONSTRAINT [FK_Highscores_Users] FOREIGN KEY([UserID])

Foreign Key to multiple tables

I've got 3 relevant tables in my database.
CREATE TABLE dbo.Group
(
ID int NOT NULL,
Name varchar(50) NOT NULL
)
CREATE TABLE dbo.User
(
ID int NOT NULL,
Name varchar(50) NOT NULL
)
CREATE TABLE dbo.Ticket
(
ID int NOT NULL,
Owner int NOT NULL,
Subject varchar(50) NULL
)
Users belong to multiple groups. This is done via a many to many relationship, but irrelevant in this case. A ticket can be owned by either a group or a user, via the dbo.Ticket.Owner field.
What would be the MOST CORRECT way describe this relationship between a ticket and optionally a user or a group?
I'm thinking that I should add a flag in the ticket table that says what type owns it.
You have a few options, all varying in "correctness" and ease of use. As always, the right design depends on your needs.
You could simply create two columns in Ticket, OwnedByUserId and OwnedByGroupId, and have nullable Foreign Keys to each table.
You could create M:M reference tables enabling both ticket:user and ticket:group relationships. Perhaps in future you will want to allow a single ticket to be owned by multiple users or groups? This design does not enforce that a ticket must be owned by a single entity only.
You could create a default group for every user and have tickets simply owned by either a true Group or a User's default Group.
Or (my choice) model an entity that acts as a base for both Users and Groups, and have tickets owned by that entity.
Heres a rough example using your posted schema:
create table dbo.PartyType
(
PartyTypeId tinyint primary key,
PartyTypeName varchar(10)
)
insert into dbo.PartyType
values(1, 'User'), (2, 'Group');
create table dbo.Party
(
PartyId int identity(1,1) primary key,
PartyTypeId tinyint references dbo.PartyType(PartyTypeId),
unique (PartyId, PartyTypeId)
)
CREATE TABLE dbo.[Group]
(
ID int primary key,
Name varchar(50) NOT NULL,
PartyTypeId as cast(2 as tinyint) persisted,
foreign key (ID, PartyTypeId) references Party(PartyId, PartyTypeID)
)
CREATE TABLE dbo.[User]
(
ID int primary key,
Name varchar(50) NOT NULL,
PartyTypeId as cast(1 as tinyint) persisted,
foreign key (ID, PartyTypeId) references Party(PartyID, PartyTypeID)
)
CREATE TABLE dbo.Ticket
(
ID int primary key,
[Owner] int NOT NULL references dbo.Party(PartyId),
[Subject] varchar(50) NULL
)
The first option in #Nathan Skerl's list is what was implemented in a project I once worked with, where a similar relationship was established between three tables. (One of them referenced two others, one at a time.)
So, the referencing table had two foreign key columns, and also it had a constraint to guarantee that exactly one table (not both, not neither) was referenced by a single row.
Here's how it could look when applied to your tables:
CREATE TABLE dbo.[Group]
(
ID int NOT NULL CONSTRAINT PK_Group PRIMARY KEY,
Name varchar(50) NOT NULL
);
CREATE TABLE dbo.[User]
(
ID int NOT NULL CONSTRAINT PK_User PRIMARY KEY,
Name varchar(50) NOT NULL
);
CREATE TABLE dbo.Ticket
(
ID int NOT NULL CONSTRAINT PK_Ticket PRIMARY KEY,
OwnerGroup int NULL
CONSTRAINT FK_Ticket_Group FOREIGN KEY REFERENCES dbo.[Group] (ID),
OwnerUser int NULL
CONSTRAINT FK_Ticket_User FOREIGN KEY REFERENCES dbo.[User] (ID),
Subject varchar(50) NULL,
CONSTRAINT CK_Ticket_GroupUser CHECK (
CASE WHEN OwnerGroup IS NULL THEN 0 ELSE 1 END +
CASE WHEN OwnerUser IS NULL THEN 0 ELSE 1 END = 1
)
);
As you can see, the Ticket table has two columns, OwnerGroup and OwnerUser, both of which are nullable foreign keys. (The respective columns in the other two tables are made primary keys accordingly.) The CK_Ticket_GroupUser check constraint ensures that only one of the two foreign key columns contains a reference (the other being NULL, that's why both have to be nullable).
(The primary key on Ticket.ID is not necessary for this particular implementation, but it definitely wouldn't harm to have one in a table like this.)
Another approach is to create an association table that contains columns for each potential resource type. In your example, each of the two existing owner types has their own table (which means you have something to reference). If this will always be the case you can have something like this:
CREATE TABLE dbo.Group
(
ID int NOT NULL,
Name varchar(50) NOT NULL
)
CREATE TABLE dbo.User
(
ID int NOT NULL,
Name varchar(50) NOT NULL
)
CREATE TABLE dbo.Ticket
(
ID int NOT NULL,
Owner_ID int NOT NULL,
Subject varchar(50) NULL
)
CREATE TABLE dbo.Owner
(
ID int NOT NULL,
User_ID int NULL,
Group_ID int NULL,
{{AdditionalEntity_ID}} int NOT NULL
)
With this solution, you would continue to add new columns as you add new entities to the database and you would delete and recreate the foreign key constraint pattern shown by #Nathan Skerl. This solution is very similar to #Nathan Skerl but looks different (up to preference).
If you are not going to have a new Table for each new Owner type then maybe it would be good to include an owner_type instead of a foreign key column for each potential Owner:
CREATE TABLE dbo.Group
(
ID int NOT NULL,
Name varchar(50) NOT NULL
)
CREATE TABLE dbo.User
(
ID int NOT NULL,
Name varchar(50) NOT NULL
)
CREATE TABLE dbo.Ticket
(
ID int NOT NULL,
Owner_ID int NOT NULL,
Owner_Type string NOT NULL, -- In our example, this would be "User" or "Group"
Subject varchar(50) NULL
)
With the above method, you could add as many Owner Types as you want. Owner_ID would not have a foreign key constraint but would be used as a reference to the other tables. The downside is that you would have to look at the table to see what the owner types there are since it isn't immediately obvious based upon the schema. I would only suggest this if you don't know the owner types beforehand and they won't be linking to other tables. If you do know the owner types beforehand, I would go with a solution like #Nathan Skerl.
Sorry if I got some SQL wrong, I just threw this together.
Yet another option is to have, in Ticket, one column specifying the owning entity type (User or Group), second column with referenced User or Group id and NOT to use Foreign Keys but instead rely on a Trigger to enforce referential integrity.
Two advantages I see here over Nathan's excellent model (above):
More immediate clarity and simplicity.
Simpler queries to write.
you can also use an enum to identify whether Owner is user or group like this:
CREATE TABLE dbo.Group
(
ID int NOT NULL,
Name varchar(50) NOT NULL
)
CREATE TABLE dbo.User
(
ID int NOT NULL,
Name varchar(50) NOT NULL
)
CREATE TYPE Enum_OwnerType AS ENUM ('Group', 'User');
CREATE TABLE dbo.Ticket
(
ID int NOT NULL,
Owner int NOT NULL,
OwnerType Enum_OwnerType NOT NULL,
Subject varchar(50) NULL
)
Maybe it's no better than any of proposed solutions, it might not offer any advantage. In fact, I think that this might require altering Enum_OwnerType and even ticket in order to change OwnerType, I guess... I hope it's useful anyway.
I have many cases like this and I just use polymorphic ability like below:
example
I have turnovers table that have this columns id, amount, user_id and I need to know the refrence of every records, So I just add two Fields table_id and table_type and my final turnovers table is like id, amount, user_id,table_id, table_type.
if new record is about order record inserted like this
[1,25000,2,22,order]
and if new record is about increment credit like this
[1,25000,2,23,credit]
note
if using M:M tables its take so much time two retrieve the records
and my way
Cons is turnovers table records number is grows up
Pons is more flexible in new records and readable and search ability
nathan_jr's 4th option (model an entity that acts as a base for both Users and Groups, and have tickets owned by that entity) doesn't enforce referential integrity on PartyId. You'd have to do that on the application layer which invites all sorts of trouble. Can't really call it an antipattern when django's genericforeignkey implements the same solution, but no doubt you can design something more robust and performant using your framework's orm (using something like django's Multi-table inheritance)
CREATE TABLE dbo.OwnerType
(
ID int NOT NULL,
Name varchar(50) NULL
)
insert into OwnerType (Name) values ('User');
insert into OwnerType (Name) values ('Group');
I think that would be the most general way to represent what you want instead of using a flag.

Resources