How to implement many-to-many relationship with shared foreign keys? - database

I am struggling with modelling my database so that entities can only have a many-to-many relationship if they share the same "parent" entity.
Here's an example:
Folders have a one-to-many relationship with Presentations.
Folders have a one-to-many relationship with Photos.
Presentations and Photos have a many-to-many relationship.
Is there a way of enforcing that Presentations and Photos are only related if they belong to the same Folder - that they share the same foreign key?

Folder holds the many-to-many relationship - related presentations and photos share the same folder, so:
create table folder (
id int,
-- other columns
);
create table presentation (
id int,
folder_id int not null references folder,
-- other columns
);
create table photo (
id int,
folder_id int not null references folder,
-- other columns
);
Join presentations and photos using folder_id.
As an example, to find photos related to a presentation:
select ph.*
from presentation pr
join photo ph on ph.folder_id = pr.folder_id
where pr.id = ?

Related

How to implement relationships with inherits at the parent table to the children tables

I'm trying to implement a database that has inheritance between some tables, there is three tables involved in the question problem: Customers, Users and Addresses (actually there is more tables involved, but with the same problem, so..).
The Customers table inherits from Users table, and the Users table has a relationship with the Addresses table (1 to many, respectively).
So My problem is that I want that table 'Customers' to has the same relationship that 'Users' has with 'Addresses', cause Customers is inherits from it. I also try to insert data to 'Addresses' with an ID from 'Customers', but this give an foreign key constraint violation, the value doesn't exists in table "myDb.users" error
this is a image of my modeling:
(Note: I'm actually using PostgreSQL, I'm just using the ADO.NET to modeling, and I know a way to get around this, but if has no way by inheritance I will change the entire DB to full relational-database.)
I assume that you're using PostgreSQL table inheritance which, unfortunately, doesn't work quite as we would expect. In particular, although records from child tables appear in selects from parent table, they are not physically recorded there, and thus their ids can't be used in foreign keys referencing parent tables.
You may consider implementing inheritance using classic approach:
CREATE TABLE Users(id INT PRIMARY KEY, user_property INT);
CREATE TABLE Customers(id INT PRIMARY KEY REFERENCES Users, customer_property INT);
CREATE TABLE Addresses(user_id INT REFERENCES Users, address TEXT);
This way you physically store properties of Customer in two tables, and you are sure that for every Customer there is a record in Users table which can be referenced from other tables.
-- inserting customer with id=1, user_property=10, customer_property=20
INSERT INTO Users(id, user_property) VALUES (1, 10);
INSERT INTO Customers(id, customer_property) VALUES (1, 20);
-- Inserting address
INSERT INTO Addresses(user_id, address) VALUES (1, 'Wall Street');
The drawback is that you need to join Users and Customers if you want to get all properties of a single customer from both tables:
-- All customer properties
SELECT * FROM Customers JOIN Users USING(id) WHERE Customers.id=1;
-- Customer and address
SELECT * FROM Customers JOIN Users USING(id) JOIN Addresses ON Users.id=Addresses.user_id WHERE Customers.id=1;

Modeling a many-to-many relationship

I have two tables, table Project and User. Below is the relationship between these two tables
A Project can be associated with multiple users
A User can operate on multiple projects
I have created below entity relationship. Is this the correct way to represent a many to many relationship?
User:
id
name
email
Project:
id
name
User_Project:
user_id
project_id
Yes, provided you have foreign key relationships (user_id) REFERENCES "user"(id) and (project_id) REFERENCES project(id) defined and a PRIMARY KEY (user_id, project_id).
BTW, try to avoid mixed case names and reserved keywords in table and column names.
Your approach is correct.
Because users can join multiple projects it is necessary to add a junction table.
Junction tables can also contain additional columns.
In your case it might be useful to know when a user joined a project.
So you could add a column join_date where you store that information.
create table users
(
id serial,
name text,
email text,
primary key (id)
);
create table projects
(
id serial,
name text,
primary key (id)
);
create table users_projects
(
user_id int,
project_id int,
join_date date,
primary key (user_id, project_id),
foreign key (user_id) references users (id),
foreign key (project_id) references projects (id)
);

Relations for Product, FrequenceOfUse and User tables

I have 3 tables:
Product (shamppoo, toothpaste,..)
FrequenceOfUse (3 times/day, once/day,...)
User
As you can imagine I want to store in a database how much the users use products. What should be the relations between those tables?
Javi
It will be a many-to-many relationship between User and Product and one-to-many relationship between FrequenceOfUse and UserProduct (the latter being a relationship itself).
Note that there is no consensus on whether relationships can have relationships on their own. So some would prefer to model it as:
Entity User
Entity Product
Entity Usage
Entity FrequenceOfUse
1-N relationship: User participates in Usage
1-N relationship: Product participates in Usage
N-1 relationship Usage is performed with Frequence
Both these models are relationally modeled as:
CREATE TABLE user (id INT NOT NULL PRIMARY KEY, name TEXT, ...)
CREATE TABLE product (id INT NOT NULL PRIMARY KEY, name TEXT, ...)
CREATE TABLE frequence (id NOT NULL, description TEXT, ...)
CREATE TABLE usage
(
user INT NOT NULL FOREIGN KEY REFERENCES (user),
product INT NOT NULL FOREIGN KEY REFERENCES (product),
frequence INT NOT NULL REFERENCES frequence,
PRIMARY KEY (user, product)
)
You may find this post in my blog useful:
What is entity-relationship model?

Linking ID from one table to data in another table

I have an assignment where I am to create two tables within a database. The tables looks like this;
ContactPerson (ID, Forename, Surname, Email, PhoneNumber)
Company (ID, CompanyName)
Now my problem is that I have to link a ContactPerson to a specific company, but I can't have them in the same table.
I understand that I can use the join statement to show both tables in one query but I need the database to know which person is linked to which company when I implement this databse into my asp.net project.
How do I do this?
You did say "specific" company so I'm assuming you have one company per person.
Put a column in the user table called CompanyID...
ALTER TABLE ContactPerson
ADD CompanyID int
(assuming your ids are ints)
and then create the following foreign key:
ALTER TABLE [dbo].ContactPerson
ADD CONSTRAINT [FK_ContactPerson_Company]
FOREIGN KEY (CompanyID)
REFERENCES Company (ID)
Shark is correct if you want a many to many relationship.
To get all people in a company:
SELECT
*
FROM
ContactPerson
WHERE
CompanyID = x
You don't HAVE to apply the foreign key constraint, but if you don't, you can accidentally put invalid data in. All a "Constraint" does is enforce a rule for you, in other words "making sure sql knows which people are in which company" as your question suggests you need to do.
The above query would work without the Foreign key constraint, but then your database doesn't "know" about the relationship.
..and if I try and insert a person with a companyid that doesn't exist, SQL will throw an error (this is a good thing).
Since this is a one-to-many relationship, I would typically put that data into the ContactPerson table. But because you explicitly say you cannot, then just create a join table:
create table ContactPersonCompany
(
ContactPersonID int not null foreign key references ContactPerson(ID),
CompanyID int not null foreign key references Company(ID)
)
Now you have a relationship between ContactPerson and Company.
Example: select all people from a particular company
select
cp.Surname,
cp.Forename
from ContactPerson cp
inner join ContactPersonCompany cpc
on cp.ID = cpc.ContactPersonID
inner join Company c
on cpc.CompanyID = c.ID
where c.CompanyName = 'Some Company'

Defining a one-to-one relationship in SQL Server

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.

Resources