Joining 3 MySQL Tables with data comparison - mysql

I have 3 MySQL tables currently in my database and I was trying to work out how to join them all together and compare data between them.
The queries form part of a "Friend or Foe" system I'm currently working on as a side project in my spare time, but I cannot for the life of me work it out. I've successfully managed a 2 table join but am getting nowhere with a 3 table join.
Anyway, here is the table layout.
Table 1
Unique ID | Username | Password | Activity
1 | SomeUser | password | Active
2 | NewUsers | password | InActive
3 | GuestUse | password | Active
Table 2
FileID | UploadedBy | Type | FileName | Description
1 | SomeUser | MP3 | Demo.mp3 | Bass Guitar Riff
2 | SomeUser | MP4 | Demo.mp4 | Some Youtube Video
Table 3
ListOwner | Friends | Foes
SomeUser | GuestUse | NULL
GuestUse | SomeUser | NULL
All I'm trying to achieve is that the "ListOwner" can view files uploaded by users who are in his/hers "friends" list, naturally there would be a page where you could view all files uploaded, but this is more designed towards seeing uploads of people you appreciate more.
In essence I am trying to get the query to read the; "Username" from Table1, "UploadeBy" from Table2 and Everything from Table3
Example:
GuestUse logs in, the query takes this information and compares his Username against Table 3 and then shows ONLY the uploads in Table2 from those who are in his friends list.
For structure the DB has the following setup.
Unique ID & Field ID are both INT(4)
Username is VARCHAR(42)
Password is VARCHAR(30)
Activity is VARCHAR(8)
ListOwner is VARCHAR(42) < Same as Username
Friends & Foes are TEXT
Any help you can give would be greatly appreciated.

Table 2 field "uploadedby" should be the numeric user id.
FileID | UploadedBy | Type | FileName | Description
1 | 1 | MP3 | Demo.mp3 | Bass Guitar Riff
2 | 1 | MP4 | Demo.mp4 | Some Youtube Video
You should create one table for "friend" relation and one for "foe" relation.
Table 3: friends
ListOwnerId | FriendId
1 | 2
1 | 3
2 | 1
Table 4: foes
ListOwnerId | FoeId
3 | 2
Then proceed with queries from inner to outer.
SELECT friendid FROM friends WHERE listowner=$loginid;
This will extract all friends for $loginid user.
If $someuseris is in $loginid friends list but $someuserid set $loginid as a foe, should $loginid see $someuserid files? Think of that. In the meanwhile, foes table is useless.
Now, select all files from friends:
SELECT * FROM files WHERE uploadedby IN (SELECT friendid FROM friends WHERE listowner=$loginid)
This query will give you a list of desired files.
This is done with a subquery, you can do it also with a join.
SELECT files.* FROM files JOIN friends ON files.uploadedby=friends.friendid WHERE friends.listowner=$loginid;

Give this a go:
select t1.Username,
t3.ListOwner,t3.Friends,t3.Foes,
t2.UploadedBy,t2.Type,t2.FileName,t2.Description
from Table1 t1
inner join Table3 t3 on t1.Username = t3.ListOwner
inner join Table2 t2 on t3.Friends = t2.UploadedBy
where Username = 'GuestUse';

Related

Trying to find duplicates and who made them

I'm working on a legacy system that allowed the insertion of multiple entries with the same email. In the people table are present entries with same name and email and also different name with an already used email (es. the user didn't know or didn't ask the email address to the person and chose to put a fake one).
A person could subscribe to a User multiple times yearly basis
They asked me for a report of which users entered the most of these entries.
Let's say I have 3 tables
| people| | subscriptions| |users|
| ------| |--------------| |-----|
| id | | id | |id |
| name | | personId | |name |
| email | | userId |
| subYear |
I found all duplicate emails and their occurrences using this query
SELECT users.name, people.email, count(subscriptions.id) nSub
FROM people
INNER JOIN (SELECT email, count(id) occurrences
FROM people
where email is not null and email != ""
GROUP BY email
HAVING occurrences > 1) duplicates
ON people.email = duplicates.email
JOIN subscriptions ON people.id = subscriptions.personId
JOIN users on users.id = subscriptions.userId
group by users.name, people.email;
but now I'm stuck when I have to integrate users, the query gives incorrect results or gets stuck in a loop.
I'm sure I'm getting the grouping wrong but I got lost
The result I'm trying to achieve is something like (based on data provided in fiddle)
|users.name| people.email | occurrences |
|----------|-------------------------|-------------|
| User1 | example#example.com | 1 |
| User2 | example#example.com | 2 |
| User2 | fake#email.com | 3 |
| User3 | fake#email.com | 1 |
Any suggestion you can give me is welcome. Thank's in advance
UPDATE: Sorry for the sloppiness, I created a fiddle
sql-fiddle

Mysql select distinct user with each of their own preference

Let's say I have a user and preference table, as well as a bridge table user_preference between the two:
/* user table: */
+----------+--------------+
| Field | Type |
+----------+--------------+
| id | int |
| username | varchar(255) |
+----------+--------------+
/* preference table: */
+------------+--------------+
| Field | Type |
+------------+--------------+
| preference | varchar(255) |
+------------+--------------+
/* user_preference table: */
+-----------------+--------------+
| Field | Type |
+-----------------+--------------+
| user_id | int |
| preference_name | varchar(255) |
+-----------------+--------------+
For instance there are 3 preferences to choose from: "swimming", "watching TV", "cycling". And one user can have zero or all 3 of the preferences, which is reflected on the user_preference table.
Now I want to query 10 different users, and with all of them each of their own preferences included, either null or mutiple preferences, how to construct a select statement for that?
So far I have tried something like this:
SELECT u.*, p.preference_name
FROM user u
LEFT JOIN user_preference p ON p.user_id = u.id
LIMIT 10;
/* Result: */
id | username | preference_name
1 | user1 | swimming
1 | user1 | cycling
2 | user2 | null
3 | user3 | watching TV
... /* rest of the result */
As you can see the result will return a duplicate user1, and it won't be 10 distinct users. I'm aware of the distinct and group by keywords, it doesn't solve the problem, as it will only return a single preference for a user, while the user can have multiple preferences.
How to do that with one single select statement?
Try this.
SELECT u.*,
GROUP_CONCAT(DISTINCT p.preference_name) AS prefs
FROM user u
LEFT JOIN user_preference p ON p.user_id = u.id
GROUP BY u.id
LIMIT 10;
The GROUP_CONCAT() will make a comma-separated list of preferences for each user.
Pro tip. When tables get very large, altering ENUMs to add more values gets very time-consuming. Plus, it's usually unwise to design a database so it needs lots of ALTER TABLE statements as it grows. So, the approach you have outlined is the right way to go if you want your possible preferences to be open-ended.

join two tables in mysql and get records

I have two tables "contacts" and "users". Users table storing data with "," separated. Need to distinct data in "Contacts" column from "Contacts" table. And need to join with "Users" table, and get the records.
Contacts Table
--------------------------
id | user_Id | contats
--------------------------
1 | 2147483647 | 90123456789,90123456789,90123456789,90123456789
2 | 2147483647 | 90123456789,90123456789,90123456789,90123456789
3 | 919444894154 | 90123456789,90123456789,90123456789,90123456789
Users Table
-----------------------------
id | username | email | phone
-----------------------------
1 | bhavan | bhavanram93#gmail.com | 90123456789
2 | bhavan | bhavanram93#gmail.com | 90123456789
3 | prince | prince#gmail.com | 1234567980
4 | bhavan | bhavanram93#gmail.com | 90123456789
5 | hello | hello#gmail.com | 1234567890
6 | bhavan | bhavanram93#gmail.com | 90123456789
Your table Contacts shouldn't be constructed this way.
Since you want 1 Users table containing all the data about a user, and 1 Contacts table containing links between different users, you'd rather do this kind of table structure :
Contacts table
id | user_id | contact_id
-------------------------
1 | 1 | 2
2 | 1 | 3
3 | 2 | 3
That'll allow you to do something like :
SELECT *
FROM Users
JOIN Contacts ON (Users.id = Contacts.contact_id)
WHERE Contacts.user_id = 1
Which will return all the data of the contacts of the user 1.
Your current structure is a huge ongoing mess, it's the opposite of being flexible.
You should restructure your db to a normalized format as Steve suggest.
But if you cant:
SELECT *
FROM Users
JOIN Contacts
ON CONCAT(',', Contacts.contacts, ',') like
CONCAT('%,', Users.phone, ',%')
WHERE Contacts.user_id = 1
the idea is you convert your contacts to
, <numbers> ,
,90123456789,90123456789,90123456789,90123456789,
and try to match with
%,90123456789,%
Note this approach cant use any index so will have bad performance with many
rows. if you are in the order of 1k-10k rows may be ok. More than that you need consider restructure your db.

SQL Tables of the Same Column to Join

I currently have a problem as how to fetch data separately, in the same table, but of different conditions.
To better illustrate, take the example below as my tables.
disputes table
id | user_to | bidder_id
1 | 1 | 2
users table
user_id | user_name
1 | userone
2 | usertwo
I'd like to have an output that combines both like this:
final output table
id | user_to | bidder_id | user_to_name | bidder_id_name
1 | 1 | 2 | userone | usertwo
I do not know how to really put it into words but I hope the illustration helps :
It seeks for the "user_to" and "bidder_id" rows, associates them to the "user_id" in the users table, where it creates two new columns that associates the "user_id" and "bidder_id" to the respective ids in the users table and fetches the user_name in the id given in the field.
LEFT JOIN is your friend. see the exsample:
sample
SELECT d.*,
utn.user_name AS user_to_name ,
bin.user_name AS bidder_id_name
FROM disputes d
LEFT JOIN users utn on utn.user_id = d.user_to
LEFT JOIN users bin on bin.user_id = d.bidder_id;

Data Between Two Tables

Excuse any novice jibberish I may use to explain my conundrum but hopefully someone here will be able to look past that and provide me with an answer to get me unstuck.
SESSIONS
+--------+---------+----------+
| id | appID | userID |
+--------+---------+----------+
| 1 | 1 | 96 |
+--------+---------+----------+
| 2 | 2 | 97 |
+--------+---------+----------+
| 3 | 1 | 98 |
+--------+---------+----------+
USERS
+--------+---------+
| id | name |
+--------+---------+
| 96 | Bob |
+--------+---------+
| 97 | Tom |
+--------+---------+
| 98 | Beth |
+--------+---------+
For each session in the Sessions table that has an appID of 1, I want to get the users name from the Users table. The Sessions userID column is linked with the Users tables id column.
So my desired result would be:
["Bob", "Beth"]
Any suggestions/help?
try this:
SELECT USERS.name FROM USERS INNER JOIN SESSIONS ON users.id = SESSIONS.userID WHERE SESSIONS.appID = 1
I would read up on http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/ for how all the joins work.
It looks like you forgot to post your code.
But in explanation.... It seems like you can just select the userID from the sessions table and then simply join the users table. Then create a WHERE clause to select all users that are attached to that ID.
Hope it helps.
If you post your code I can probably help you out more and if this doesnt seem just right lemme know and ill help you how i can
You need to create a join table (http://www.tutorialspoint.com/postgresql/postgresql_using_joins.htm) and then request the data using the equal operator.
SELECT USERS.name FROM USERS, SESSIONS WHERE SESSIONS.userID = USERS.ID ;