For a small shift management project I decided to make I'm trying to make a weekly schedule of shifts for our employees, based on a 3 shifts per day schedule, where 1 shift can hold more than one employee.
I've created an employee table and a work_day table that holds the date of the shift and 3 join tables for each shift of the day.
CREATE TABLE employee(
id SERIAL PRIMARY KEY,
"name" VARCHAR(128) NOT NULL,
archived BOOLEAN DEFAULT FALSE
);
CREATE TABLE work_day(
id SERIAL PRIMARY KEY,
"date" DATE NOT NULL UNIQUE
);
CREATE TABLE morning_shift(
employee_id INTEGER FOREIGN KEY REFERENCES employee(id),
shift_id INTEGER FOREIGN KEY REFERENCES work_day(id),
PRIMARY KEY(employee_id, shift_id)
);
CREATE TABLE evening_shift(
employee_id INTEGER FOREIGN KEY REFERENCES employee(id),
shift_id INTEGER FOREIGN KEY REFERENCES work_day(id),
PRIMARY KEY(employee_id, shift_id)
);
CREATE TABLE night_shift(
employee_id INTEGER FOREIGN KEY REFERENCES employee(id),
shift_id INTEGER FOREIGN KEY REFERENCES work_day(id),
PRIMARY KEY(employee_id, shift_id)
);
The plan I had in mind is to create a view that would materialize a presentation of a work day:
Date
Morning Shift(name1, name2)
Evening Shift(name3, name4)
Night Shift(name5)
That way I can query whole work days as objects in my projects.
The issue is I come with very little experience in databases and it has been proved way more difficult that I had even imagined. I've been trying for the last couple of days and finally gave up on my ego and now I seek your humble help, how do you create a view like that. There are many confusing joins to it I can't wrap my head around it.
Thank you very much in advance.
As others mentioned in the comments, there is room for improvement regarding the DB design. However, this is how to create a view, just join all the tables where you need data from and select the fields you want:
CREATE VIEW shifts AS
SELECT *
FROM work_day inner join morning_shift on work_day.id = morning_shift.shift_id
inner join evening_shift on work_day.id = evening_shift.shift_id
... (more joins)
Take a look at this Postgres tutorial page on joins
Related
I'm trying to create a foreign key between two tables. Problem is one of those tables has a composite primary key..
My tables are products (one row per product) and product_price_history (many rows per product).
I have a composite key in product_price_history, which is product id and start date of a specific price for that product.
Here's my code :
CREATE TABLE products (
product_id INT IDENTITY(1,1) PRIMARY KEY,
product_name VARCHAR(50) NOT NULL,
product_desc VARCHAR(255) NULL,
product_group_id INT
)
CREATE TABLE product_price_history (
product_id INT NOT NULL,
start_date DATE NOT NULL,
end_date DATE NULL,
price NUMERIC (6,2) NOT NULL
)
ALTER TABLE product_price_history
ADD CONSTRAINT pk_product_id_start_dt
PRIMARY KEY (product_id,start_date)
Now I'm trying to create a foreign key between the products table and the product_price_history table but I can't because its a composite key.
Also it doesn't make sense to add the start date (the other part of the foreign key) to the products table.
What's the best way to deal with this? Can I create a foreign key between these tables? Do I even NEED a foreign key?
My intentions here are
to enforce uniqueness of the product price information. A product can only have one price at any time.
to link these two tables so there's a logical join between them, and I can show this in a database diagram
The foreign key on the product_price_history table should only include product_id. Your target is to ensure that any entry product_price_history already has "parent" entry in products. That has nothing to do with start_date.
The way I see this situation, in theory, fully normalized version of the tables would have to have current_price as unique value in products table. And the product_price_history is simply a log table.
It's not necessary to do it this way, with a physical field, but thinking from this perspective helps to see where your tables model is slightly de-normalized.
Also, if you make product_price_history table anything but simple log table, how do you ensure that new start_date is newer than previous end_date? You can't even express that as a primary key. What if you edit start_date later? I would even think to create different compaund key for product_price_history table. Perhaps product_id+insert_date or only auto-increment id, while still keeping foreign key relationship to the products.product_id.
I have 4 SQL tables: User, Student, Professor and Publication.
User has the common columns for any kind of user;
Student has columns specific for a student;
Professor has columns specific for a professor;
Publication is only for professors.
So I have:
create table dbo.[User] (
Id int identity not null
constraint PK_User_Id primary key clustered (Id),
-- Other user columns
)
create table dbo.Student (
UserId int not null
constraint PK_Student_UserId primary key clustered (Id),
-- Other student columns
)
create table dbo.Professor (
UserId int not null
constraint PK_Professor_Id primary key clustered (Id),
-- Other student columns
)
create table dbo.Publication (
Id int identity not null
constraint PK_Publication_Id primary key clustered (Id),
UserId int not null
-- Other student columns
)
alter table dbo.Student
add constraint FK_Student_UserId foreign key (UserId) references dbo.[User](Id);
alter table dbo.Professor
add constraint FK_Professor_UserId foreign key (UserId) references dbo.[User](Id);
alter table dbo.Publication
add constraint FK_Publication_UserId foreign key (UserId) references dbo.Professor(Id);
QUESTION
Should I have a column Id as PK in Professor and Student tables?
And make, for example, (Id, UserId) as the PK of Professor (Same for student)
Then Publication would reference Professor.Id and not Professor.UserId.
I am asking this because it sounds strange to have Publication to reference UserId from Professor table which can be confusing when I will have more tables.
Could someone please advice me on this?
In your current schema arrangement and without knowing your use cases (programmatically), one could make the argument that you don't need the Id identity columns for any of the extension tables. I assume this would be a 1 to 1 relationship to the User table anyway, so you'd at least want a unique constraint on the UserID columns, which you'd get by making it a PK anyway.
Things I like to consider are:
Can a professor ever become a different user ?
Is it possible for a professor to exist without an user ?
Is it possible for a single user to be two professors (multiple disciplines?)
If so, why wouldn't you give every professor an unique Id (ProfessorId), and only create a foreign key to the User table (UserId, you could call this UserFk).
In the publication table you can reference the professor by his/her id and call this one ProfessorFk. This way you create very efficient references between tables. The publication table than also gets a single PublicationId as primary key.
Correct me if i'm wrong, i don't know your use case. But it would seem reasonable that a professor can have multiple publications, but a publication can also be written by multiple professors ? This would mean you need an extra table between publication and professor for the n-n relationship.
About creating a professor key that is a combined key (Id, UserId). I personally dislike combined keys, if you want to reference this professor from your publication table you need two columns.
This would also suggest you can have multiple professors for the same user, if so, go for the single Id option.
This means i would create the following setup:
User Table
UserId
Student Table
StudentId
UserFk
Professor Table
ProfessorId
UserFk
ProfessorPublication Table
ProfessorFk
PublicationFk
Publication Table
PublicationId
So, it partly is based on what you want to be able to do with your data, and partly just your preference.
I have a data for rubber belts where one compound has many chemicals and these many chemicals can be combined in any combination to form a new compound(one chemical in many compounds). I have created one table for compounds and one for chemicals. How do i form a relational table without huge repeat of data?
No doubt there's a huge number of tutorials on the net if you do a search. You should do some research or get a good database text. To help you out here's an example of your many to many relationship realised as one to many tables with an associated CompoundChemical table.
CREATE TABLE Compound
(
CompoundId INT NOT NULL PRIMARY KEY,
Name VARCHAR(100) NOT NULL
);
CREATE TABLE Chemical
(
ChemicalId INT NOT NULL PRIMARY KEY,
Name VARCHAR(100) NOT NULL
)
CREATE TABLE CompoundChemical
(
CompoundId INT NOT NULL,
ChemicalId INT NOT NULL,
PRIMARY KEY (CompoundId, ChemicalId),
FOREIGN KEY fk1 (CompoundId) REFERENCES Compound(CompoundId),
FOREIGN KEY fk2 (ChemicalId) REFERENCES Chemical(ChemicalId)
)
Adding table structures will help but you can probably go with something like this
Creating one table for compounds and one for chemicals is good but you'll most probably need one more table because there is no fixed number of chemicals in each compound.
Maybe table named Substances that has following columns that reference chemicals and compunds. (ChemicalID, CompoundID)
I am trying to figure out the way of creating table without a foreign key under sqlite. I would like to avoid the use of foreign key due its incompatibility under some applications I am working now.
Could anyone please show a simple example with maybe two tables? Thank you.
Simple example: How do I select all tracks from one specific artist?
CREATE TABLE artist(
artistid INTEGER PRIMARY KEY,
artistname TEXT
);
CREATE TABLE track(
trackid INTEGER,
trackname TEXT,
trackartist INTEGER
);
You can have relationships between tables without declaring a foreign key. You simply do
SELECT a.*, t.* FROM artist a INNER JOIN track t ON a.artistid = t.trackartist;
(substituting the actual columns you want in place of a.*, t.*).
You can do this without declaring that trackartist is a foreign key to artist(artistid). If you do make that declaration, the difference is that SQLite will ensure that you never put a value in trackartist that is not a valid artistid and that you never change or remove an artistid that is used in trackartist.
Foreign keys are a mechanism to maintain the integrity of the association between tables but you can "create" any association you want in a SELECT statement independent of any primary or foreign keys declared in the database.
If you don't specify a foreign key, then there is no foreign key.
SELECT t.trackname, t.trackid
FROM track t
INNER JOIN artist a
ON a.artistid = t.trackartist
WHERE a.artistname = 'Alex'
I need to define a one-to-one relationship, and can't seem to find the proper way of doing it in SQL Server.
Why a one-to-one relationship you ask?
I am using WCF as a DAL (Linq) and I have a table containing a BLOB column. The BLOB hardly ever changes and it would be a waste of bandwidth to transfer it across every time a query is made.
I had a look at this solution, and though it seems like a great idea, I can just see Linq having a little hissy fit when trying to implement this approach.
Any ideas?
One-to-one is actually frequently used in super-type/subtype relationship. In the child table, the primary key also serves as the foreign key to the parent table. Here is an example:
CREATE TABLE Organization
(
ID int PRIMARY KEY,
Name varchar(200),
Address varchar(200),
Phone varchar(12)
)
GO
CREATE TABLE Customer
(
ID int PRIMARY KEY,
AccountManager varchar(100)
)
GO
ALTER TABLE Customer
ADD FOREIGN KEY (ID) REFERENCES Organization(ID)
ON DELETE CASCADE
ON UPDATE CASCADE
GO
Why not make the foreign key of each table unique?
there is no such thing as an explicit one-to-one relationship.
But, by the fact that tbl1.id and tbl2.id are primary keys and tbl2.id is a foreign key referenceing tbl1.id, you have created an implicit 1:0..1 relationship.
Put 1:1 related items into the same row in the same table. That's where "relation" in "relational database" comes from - related things go into the same row.
If you want to reduce size of data traveling over the wire consider either projecting only the needed columns:
SELECT c1, c2, c3 FROM t1
or create a view that only projects relevant columns and use that view when needed:
CREATE VIEW V1 AS SELECT c1, c2, c3 FROM t1
SELECT * FROM t1
UPDATE v1 SET c1=5 WHERE c2=7
Note that BLOBs are stored off-row in SQL Server so you are not saving much disk IO by vertically-partitioning your data. If these were non-BLOB columns you may benefit form vertical partitioning as you described because you will do less disk IO to scan the base table.
How about this. Link the primary key in the first table to the primary key in the second table.
Tab1.ID (PK) <-> Tab2.ID (PK)
My problem was I have a 2 stage process with mandatory fields in both. The whole process could be classed as one episode (put in the same table) but there is an initial stage and final stage.
In my opinion, a better solution for not reading the BLOB with the LINQ query would be to create a view on the table that contains all the column except for the BLOB ones.
You can then create an EF entity based on the view.