How do you model a typical friend-to-friend relationship in a relational database? - sql

What is the appropriate way of modeling a friend-to-friend relationship in a relational database? I'll detail out what I mean by a friend-to-friend relationship below.
friend-to-friend relationship
Assuming we have a table with persons. These persons can be friends with each other. Being a friend means that a person and another person are connected through a relationship that only includes those two persons.
My best, not satisfactory, idea so far
A table containing persons
A table containing the relationships
A table containing the many-to-many-relationship between persons and
relationships
As in the image below.
proposed data model
This seems fine from a data-modeling perspective, but when writing a SQL query that would check whether two given person_ids are friends or not, the query becomes rather complex, which makes me think this is not the appropriate way to do it.

i would recommend a table with two person_id-columns and maybe a relationshiptype-id for different relationships

create table individuals (
individual_id int primary key,
full_name varchar(255)
);
create table relationships (
from_individual_id int references individuals(individual_id),
type varchar(255) check (type in ('FRIEND OF')), -- should be a lookup table
to_individual_id int references individuals(individual_id),
primary key (from_individual_id, to_individual_id, type),
check (from_individual_id <> to_individual_id)
);
I can think that you are my friend, but you don't think I am your friend...
But generally "from" thinks "to" is a friend and vice-versa, so you'll to add the reverse relationship as another row

I would go for [Friend - Friend - Relationship] link table.
[Friend]---[Link_table]---[Relationship]
|
[Friend]
:)
EDIT:
Where for example [Table]: columns...
[Friend]: PK_Friend, Name, LastName
[Link]: PK_Link, PK_Friend1, PK_Friend2, PK_RelationShip
[RelationShip]: PK_RelationShip, RelationShipDescription

Related

SQL database structure with two changing properties

Let's assume I am building the backend of a university management software.
I have a users table with the following columns:
id
name
birthday
last_english_grade
last_it_grade
profs table columns:
id
name
birthday
I'd like to have a third table with which I can determine all professors teaching a student.
So I'd like to assign multiple teachers to each student.
Those Professors may change any time.
New students may be added any time too.
What's the best way to achieve this?
The canonical way to do this would be to introduce a third junction table, which exists mainly to relate users to professors:
users_profs (
user_id,
prof_id,
PRIMARY KEY (user_id, prof_id)
)
The primary key of this junction table is the combination of a user and professor ID. Note that this table is fairly lean, and avoids the problem of repeating metadata for a given user or professor. Rather, user/professor information remains in your two original tables, and does not get repeated.

How to write a recursive query for a self referencing table and junction table (duh)

1. Diagram
I have a table entity that references itself. Since it's a 1-M relationship, I created a junktion table relation entity.
2. Table Entity
TABLE ENTITY (ID INTEGER PRIMARY KEY, ID_ENTITY, wiki_title TEXT);
2.1 Sample
Id |ID_ENTITY| wiki_title
19127|m.06w4why|Sterling_Hill_Historic_District
19128|m.017ym9|Saint_John_County,_New_Brunswick
19129|m.0jl0r_0|Sheshnag_Lake
3. Relation_entity
CREATE TABLE RELATION_ENTITE (ID INTEGER PRIMARY KEY, ID_SOURCE TEXT, ID_DESTINATION TEXT NOT NULL, FOREIGN KEY(ID_SOURCE) REFERENCES ENTITE(ID_ENTITE), FOREIGN KEY(ID_DESTINATION) REFERENCES ENTITE(ID_ENTITE));
3.1 Sample
As you can see in the following sample m.06w4why has a relation with three other entities, namely: m.01x73, m.0rg75 and m.0rg9n.
ID |id source| id_destination
119647|m.06w4why|m.01x73|
119648|m.06w4why|m.0rg75|
119649|m.06w4why|m.0rg9n|
119650|m.06w4why|m.05gk2h0|
119651|m.017ym9|m.074r0|
119652|m.017ym9|m.059s8|
119653|m.0jl0r_0|m.02p8px5|
119654|m.0jl0r_0|m.0f5wwn|
4. Question
The values in id_destination will in turn become id_source. My question is how far can I go deep in the database in order to retrieve all the relations.
For example for m.06w4why I want to retrieve all the relations that start from m.01x73, m.0rg75 and m.0rg9n and combine them together.
Note
It's a very hard question I think. So please le me know if it's unclear. And it wayyy beyond my reach lol
thank you.
Assume you have a table sources with a column id.
The query to get the destinations for these particular sources would be as follows:
SELECT id_destination
FROM relation_entite
JOIN sources ON relation_entite.id_source = sources.id;
Then just plug this into a CTE, to get the basic recursive CTE for searching a subtree:
WITH RECURSIVE ids(id) AS (
VALUES('m.06w4why') -- start with this record
UNION ALL
SELECT id_destination -- get destinations for any previous sources
FROM relation_entite
JOIN ids ON relation_entite.id_source = ids.id
)
SELECT id FROM ids;
(If it is possible that there are loops in the data, you must use UNION instead of UNION ALL.)

A field referencing two tables - Foreign Key Conflict

Please check the tables below for a simplified version of my problem:
Table Boys
BoyId
BoyName
...
Table Girls
GirlId
GirlName
Table Toys
ToyId
ToyName
ToyOwnerBoyOrGirl ( The toy could be owned by a boy or a girl)
ToyOwnerId
I created two constraints:
1) ToyOwnerId is a foreign key of the Primary Key Boys.BoyId
2) ToyOwnerId is a foreign key of the Primary Key Girls.GirlId
My purpose is to tell the database that ToyOwnerId will always be one of these Ids
My problem:
When I tried to insert a new Toy with an id of a Boy, I got an error that there is a foreign key conflict in the Girls constraint.
Is this a bag design or I can still use the same design with a fix ?
I think you should combine the boys and girls table to one table called children. It would have sex column that would have an M or F. That will simplify things.
You should simply have both IDs in your toys table plus a check constraint to ensure that always either a boy or a girl is the owner.
Table Toys
ToyId
ToyName
ToyOwnerBoyId
ToyOwnerGirlId
CONSTRAINT chkToyOwner CHECK
(
(ToyOwnerBoyId is null and ToyOwnerGirlId is not null)
OR
(ToyOwnerBoyId is not null and ToyOwnerGirlId is null)
)
As to selecting the data, use outer joins:
select ...
from toys
left join boys on boys.boyid = toys.toyownerboyid
left join girls on girls.girlid = toys.toyownergirlid;
To find toys owned by boys:
select ...
from toys
where toyownerboyid is not null;
It looks like a bad design. Why don't have one table for all children and some mark - is it boy or girl? Also I really doubt you need ToyOwnerBoyOrGirl field - as it can be easily obtained by join from toys to owners.
Consider following scheme:
Table Children
ID
Name
Is_Boy
Table Toys
ID
Name
Owner_ID
In this case you need just foreign key from toys to owners, and other tasks you might encounter will be much more simplier to solve.
EDIT: As per OP's comment - Boys and Girls tables are totally different.
So, in this case you still can have table Children (let's use previous terminology) as a "common" table for Boys and Girls.
Something like:
Table Children
ID
Table_Name ('Boys' or 'Girls' here)
Record_ID (ID from Boys or Girls respectively)
...maybe some common fields from boys and girls tables here...
Table Boys
ID
Child_ID
...the rest of fields
Table Girls
ID
Child_ID
...the rest of fields
It's a bad design, given the fact one column set (one column, being ToyOwnerId) is referred to different tables, both as a one-column FK to a one-column PK. The obvious question would then be : how come you have different tables with a similar PK ? And I see you have answered that already, by means of replying the data columns of the respective tables are different. That is a good reason to have different tables. But, then, how to solve the FK issue ? (I understood that these "boys" and "girls" are not the real entities). What you can do, is make a BoyToy and a GirlToy table. If you have very few data columns (data = non-PK and non-FK) then that is a perfect solution. No ?

SQL database design pattern for user favorites?

Asked this on the database site but it seems to be really slow moving. So I'm new to SQL and databases in general, the only thing I have worked on with an SQL database used one to many relationships. I want to know the easiest way to go about implementing a "favorites" mechanism for users in my DB-similar to what loads of sites like Youtube, etc, offer. Users are of course unique, so one user can have many favorites, but one item can also be favorited by many users. Is this considered a many to many relationship? What is the typical design pattern for doing this? Many to many relationships look like a headache(I'm using SQLAlchemy so my tables are interacted with like objects) but this seems to be a fairly common feature on sites so I was wondering what is the most straightforward and easy way to go about it. Thanks
Yes, this is a classic many-to-many relationship. Usually, the way to deal with it is to create a link table, so in say, T-SQL you'd have...
create table user
(
user_id int identity primary key,
-- other user columns
)
create table item
(
item_id int identity primary key,
-- other item columns
)
create table userfavoriteitem
(
user_id int foreign key references user(user_id),
item_id int foreign key references item(item_id),
-- other information about favoriting you want to capture
)
To see who favorited what, all you need to do is run a query on the userfavoriteitem table which would now be a data mine of all sorts of useful stats about what items are popular and who liked them.
select ufi.item_id,
from userfavoriteitem ufi
where ufi.user_id = [id]
Or you can even get the most popular items on your site using the query below, though if you have a lot of users this will get slow and the results should be saved in a special table updated on by a schedules job on the backend every so often...
select top 10 ufi.item_id, count(ufi.item_id),
from userfavoriteitem ufi
where ufi.item_id = [id]
GROUP BY ufi.item_id
I've never seen any explicitly-for-database design patterns (except a couple of trivial misuses of the phrase 'design pattern' when it became fashionable some years ago).
M:M relationships are OK: use a link table (aka association table etc etc). Your example of a User and Favourite sounds like M:M indeed.
create table LinkTable
(
Id int IDENTITY(1, 1), -- PK of this table
IdOfTable1 int, -- PK of table 1
IdOfTable2 int -- PK of table 2
)
...and create a UNIQUE index on (IdOfTable1, IdOfTable2). Or do away with the Id column and make the PF on (IdOfTable1, IdOfTable2) instead.

Create foreign key with non unique column in SQL Server

I am dealing with a table that contains both cars and owners (table CO). I am creating another table to contain attributes for an owner (table OwnerAttributes), that a user can assign to through a GUI. My problem lies in the fact that owners are not unique and since I am using SQL Server I cannot create a foreign key on them. There is an id in the table, but it identifies the car and owner as a whole.
The idea I had to get around this problem is to create a new table (table Owners) that contains distinct owners, and then adding a trigger to table CO that would update the Owners with any changes. I can then use table Owners for my OwnerAttributes table and solve my problem.
The question I want answered is if there is a better way to do this?
I am using a preexisting database, that is heavily used by an old application. The application is hooked up to use the table CO for owners and cars. There also exists several other tables that use the CO table. I wish I could split the table into Owners and Cars, but the company doesn't want me to spend all my time doing it as there are several more features I need to add to the application.
Your thoughts on the Owners table are on the right track! Your problem is because your schema is not normalized. It's the fact you're storing two things (cars, and owners) in one table (your table CO).
You are correct that you should make an Owner table, but you should then remove the Owner information from the CO table entirely, and replace it with a foreign key to the Owners table.
So you want something like this:
CREATE TABLE Owner (
ownerID int not null primary key indentity(1,0),
FirstName varchar(255),
LastName varchar(255),
/* other fields here */
)
GO
CREATE TABLE Car
carID int not null primary key identity(1,0),
ownerID int not null references Owner(ownerID),
/* other fields go here */
GO
/* a convenience, read only view to replace your old CAR OWNER table */
CREATE VIEW Car_Owner AS
SELECT c.*, o.FirstName, o.LastName FROM Car c INNER JOIN Owner o ON c.ownerID = o.ownerID
Now, you have everything properly normalized in SQL. A view has given you back the car_owner as one thing in a pseudo-table.
But the real answer is, normalize your schema. Let SQL do what it does best (relate things to other things). Combining the two things on one table will just lead to more problems like you're encountering downstream.
Hopefully this answer seems helpful and not condescending, which is what I was going for! I have learned the hard way that this approach (normalize everything, let the database do some extra work to retrieve/display/insert it) is the only one that works out in the end.
You should create Owner table, Car table, OwnerCar table(if person can has a few cars). Owner table contains fields, that describe owner(owner properties)