How to JOIN two FKs from a table to another table? - mysql

I have a table of many-to-many relationships as:
Table relationship:
relationship_id,
first_user REFERENCES users(user_id),
second_user REFERENCES users(user_id),
Table users:
user_id,
other user information
To read friends of a given user (which can be in first_user or second_user), I need to JOIN two tables (relationships and users), but two columns of the table relationships are FK
Question 1: How can I JOIN two tables to use both FKs?
I have a table for pending requests which is similar to the table relationships. Upon approving a request, it will be deleted from requests and INSERTed into relationships.
Question 2: How can I JOIN three tables to retrieve connection and pending requests in one query.

You will have to give the instances of the "users" table aliases, so you can refer to them serparately:
SELECT u1.*, u2.* FROM relationship r
JOIN users u1 ON (u1.user_id = r.first_user)
JOIN users u2 ON (u2.user_id = r.second_user)
To select both from requests and relationships, you can use a UNION:
SELECT u1.*, u2.* FROM relationship r
JOIN users u1 ON (u1.user_id = r.first_user)
JOIN users u2 ON (u2.user_id = r.second_user)
UNION
SELECT u1.*, u2.* FROM requests r
JOIN users u1 ON (u1.user_id = r.first_user)
JOIN users u2 ON (u2.user_id = r.second_user)

To use both foreign keys, you need two joins (one for each):
select *
from relationship r
inner join users u1 on (u1.user_id = r.first_user)
inner join users u2 on (u2.user_id = r.second_user)

The {relationship_id, first_user, second_user} table contains a repeating group.
Just remove one of them (that makes relationship_id non-unique) and add a surrogate key (or add userid to the primary key).
CREATE TABLE relationships
( id INTEGER NOT NULL PRIMARY KEY
, relationship_id INTEGER NOT NULL
, user_id INTEGER NOT NULL REFERENCES users(user_id)
);
It would be a nice homework assignment to try to generate constraints for this construct.
Another way (for binary relations like marriages) is to put the "significant Other" link in the users table:
CREATE TABLE lusers
( luser_id INTEGER NOT NULL PRIMARY KEY
, magnificent_other INTEGER REFERENCES lusers (luser_id)
...
);
As a side effect, this will also make bigamy impossible.
Again: nice homework assignment to implement the constraints.

Related

How to select entries in a join table based on the aggregate selection of data from several other tables?

I have an application based on 4 MySQL tables:
persons
------------
id -- Primary key, unique
name
entity_id -- foreign key => entities
entities
------------
id -- Primary key, unique
name
company_id -- foreign key => companies
companies
------------
id -- Primary key, unique
name
persons_linked_companies -- join table : persons <=> companies
--------------------------
id -- Primary key, unique
persons_id -- foreign key => persons
companies_id -- foreign key => companies
Each "person" belong to an "entity"
Each "entity" belong to a "company"
A "person" can only have one "entity"
An "entity" can only have one "company"
A "person" can be linked to one or more third parties (meaning other companies). For this there is a join table called "persons_linked_companies"
A person can have multiple linked companies, but a person shouldn't be linked to his own company
I can't figure out what kind of subquery/join I should issue to get the following data:
I need to select entries in the join table "persons_linked_companies" to get all persons whose linked company is the same has the company they belong to (because of bullet point 6).
Pseudo code below:
select id from persons_linked_companies where companies_id = (select id from companies where persons.entity.company_id = persons_linked_companies.companies_id)
Besides using aliases. you can join all tables
But this would only yield a result, if you entered such a row in the table persons_linked_companies, which should be not be done by your rule 6
SELECT
id
FROM
persons_linked_companies pcl
WHERE
companies_id = (SELECT
c.id
FROM
companies c
INNER JOIN entities e ON e.company_id = c.id
INNER JOIN persons p ON p.entity_id = e.id
WHERE
p.id = pcl.persons_id)

Microsoft Access SQL Joins

List all players and their ages for their associated current team for teams that have a manager.
Here are my 3 Tables and their attributes
PLAYER
PLAYERNUM Primary Key
PLAYERNAME
PlayerAge
TEAM
TEAMNUM Primary Key
TEAMNAME
TeamCity
MgrNum
AFFILIATION
PLAYERNUM Primary Key/Foreign Key
TEAMNUM Primary Key/Foreign Key
AffilYrs
AffilBatAvg
AffilDateStart Foreign Key
AffilDateEnd
AffilCurrentTeam
Here is my SQL:
SELECT PLAYERNAME, PlayerAge
FROM PLAYER INNER JOIN AFFILIATION
ON PLAYER.PLAYERNUM = AFFILIATION.PLAYERNUM
INNER JOIN TEAM
ON AFFILIATION.TEAMNUM = TEAM.TEAMNUM
WHERE MgrNum IS NOT NULL;
I am given the error missing operator in query expression
Perhaps it should be;
[NotTested]
SELECT PLAYERNAME, PlayerAge
FROM (PLAYER INNER JOIN AFFILIATION
ON PLAYER.PLAYERNUM = AFFILIATION.PLAYERNUM)
INNER JOIN TEAM
ON AFFILIATION.TEAMNUM = TEAM.TEAMNUM
WHERE MgrNum IS NOT NULL;
GROUP BY PLAYER.PLAYERNAME, PLAYER.PlayerAge
You should use parentheses for multiple joins in access.

How to make many to many relationship table efficient for SELECT queries in MySQL?

A user can have many interests.
An interest can be interested to many users.
My database looks like that:
Users table:
id - primary key,
name,
email,
Interests table:
id - primary key,
title
Users_To_Interests table:
id - primary key,
user_id(id from users table)
interest_id(id from interests table)
How can I improve Users_To_Interests table to be able to pick all users who have the same interest efficiently? user_id and interest_id columns don't have indexes or keys. If I need to add them, please show me how can I make that.
Edition 1: For example,
user1 has interests : interest1, interest2, interest3;
user2 has interests : interest3, interest4;
user3 has interests : interest3, interest5;
user4 has interests : interest4;
If I want to get all users who have interest1, I should receive user1;
If I want to get all users who have interest2, I should receive user1;
If I want to get all users who have interest3, I should receive user1, user2, user3;
The query to get users for interest #3 is very simple (use IN or EXISTS). With an index on users_to_interests(interest_id, user_id) this should be very fast.
select *
from users
where id in (select user_id from users_to_interests where interest_id = 3);
Here is a query which would find all users having interests 1 and 2. It should be clear how to generalize this to any number of interets. The subquery aggregates over users and finds those users who have the interests we want. We then join this back to the Users table to get the full information for each user.
SELECT
t1.*
FROM Users t1
INNER JOIN
(
SELECT ui.user_id
FROM Users_To_Interests ui
INNER JOIN Interests i
ON ui.interest_id = i.id
WHERE i.title IN ('interest2', 'interest3')
GROUP BY ui.user_id
HAVING COUNT(DISTINCT i.id) = 2
) t2
ON t1.id = t2.user_id;

How to display information from a referencing table?

There is probably a very simple solution to this, but I couldn't figure out an appropriate way to google it.
I have three tables in my database.
The first one is "customer" and it has (ID, Name, Username etc)
The second one is "attraction" and it has (AttractionID, Name, Location, etc..)
The tird one "favourites" is made in order for the user to save favourites from the second table with the user ID from the first one:
Here is the third table:
CREATE TABLE Favorites (
FavID INT NOT NULL,
ID INT NOT NULL,
AttractionID INT NOT NULL,
PRIMARY KEY (FavID),
FOREIGN KEY (ID) REFERENCES customer(ID),
FOREIGN KEY (AttractionID) REFERENCES attraction(AttractionID)
);
I can insert into the table but what sql query do I need to use in order to show information from the referencing tables?
Lets say the user has saved their user ID and favourite attraction ID to the favourite table, how can I display the name and location from the attraction table that corespond to the foreign key attractionID saved in the favourites table?
Thanks
You should use JOIN for it:
SELECT * FROM Favorites f
INNER JOIN Attraction a ON f.AttractionId = a.AttractionId
INNER JOIN customer c ON f.Id = c.id
f, a and c are just aliases to make the referencing simpler, you could also write
SELECT * FROM Favorites
INNER JOIN Attraction ON Favorites.AttractionId = Attraction.AttractionId
INNER JOIN customer ON Favorites.Id = customer.id
or with AS, which makes it a bit more clear (but longer, so I prefer the first way)
SELECT * FROM Favorites AS f
INNER JOIN Attraction AS a ON f.AttractionId = a.AttractionId
INNER JOIN customer AS c ON f.Id = c.id

SQL - How do I get name using a number from a different table?

Below is my create tables for a database using SQL.
I can't figure out how to get a name displayed for both ID and LIKED from the likes table.
This assignment should be simple, be able to display the names of people that like each other. There is a data entry form that requires IDs to be entered for the people that like each other, but then I have to display the names of both of the people that like each other.... I hope I didn't make this confusing.
Is it possible for some SQL code to display the names of who likes who.
CREATE TABLE person
(
ID INT PRIMARY KEY,
NAME VARCHAR(50)
) engine=innodb;
CREATE TABLE likes
(
ID INT,
LIKED INT,
constraint likesPK primary key(ID,LIKED),
constraint personFK foreign key(ID) references person(ID)
on delete cascade on update cascade,
constraint nameFK foreign key(LIKED) references person(ID)
on delete cascade on update cascade
) engine=innodb;
Example of what I have tried to do but needs one more column to display the person "LIKED":
select B.id, B.name, A.lIKED from likes A, person B where A.id=B.id AND A.id = 1;
First, I wave my finger in your general direction. Programming requires precision and your phrase, "using sql" was vague. If you meant sql server say so. In fact, edit your post and add the appropriate tag.
Second, your on delete cascades are in the wrong place. In fact, in this scenario, on delete cascades are probably a very bad idea.
Third, what was that again? Oh yes your question. How do I show people who like each other? Probably something like this:
select p1.whatever, p2.whatever
from person p1 -- this would be me
join likes l1 on p1.id = l1.id -- this is who I like, which is you
join likes l2 on l1.liked = l2.id -- this is who you like, which is me
join person p2 on l2.id = p2.id -- this is you
etc
By the way, I didn't think it was simple.
try this
select b.id, b.name, (select name from person where id = a.liked)
from likes a join person b
on a.id = b.id
where b.id = some id AND b.id = a.id
Seems like your like table should have two references to the person table (making it an intermediate/pivot table); basically, one "like-ee" and one "like-or". So like should probably look like this:
like
--------------
ID int
PersonWhoLikedID int
PersonWhoWasLikedID int
Then your query turns into this:
SELECT B.name, C.name AS `Liked Person`
FROM likes
LEFT JOIN person B ON likes.PersonWhoLikedID = B.ID
LEFT JOIN person C ON likes.PersonWhoWasLikedID = C.ID