select user with more than one category - mysql

now here I have these tables, user can have more than category, and I want to show table like this
I've wrote this statement but It repeats user name with every category
SELECT
c.name
FROM
permission p
JOIN users u
ON u.id = p.user_id
JOIN category c
ON c.id = p.category_id
USER DATA TABLE // this table is what I want to get because every user have more than one category
username
email
categories
row
row
math, science
row
row
row, row, row
//those tables are what I have in the database
USERS TABLE
USER ID
username
email
5
row
row
6
row
row
CATEGORY TABLE
C ID
C NAME
8
math
9
science
PERMISSION TABLE
ID
USER ID
C ID
1
5
8
2
6
9

If you have only username use DISTINCT
SELECT DISTINCT
c.name
FROM
permission p
JOIN
users u ON u.id = p.user_id
JOIN
category c ON c.id = p.category_id
With more columns you should look for GROUP BY c.name

As user info in users table is unique so max keyword is used for optimization purpose. If same category is mapped multiple times with single user then use DISTINCT keyword inside GROUP_CONCAT functions. GROUP_CONCAT() is build in function for MySQL.
-- MySQL
SELECT MAX(u.username) username
, MAX(u.email) email
, GROUP_CONCAT(c.cname) categories
FROM users u
INNER JOIN permission p
ON u.userid = p.userid
INNER JOIN category c
ON c.cid = p.cid
GROUP BY u.UserID;

Related

How to Join three tables properly

The main table has 4 columns:
User Activity Table
userActivityId userId therapistId activityId
1 1 1 1
Each of these columns is a table and these values are all foreign keys.
Basically im trying to run a query that will join to the users table and pull their first and last name based off the user Id.Same thing with therapist - join to the therapist table, pull first + last name.And finally Join to the Activity table and pull the activity name and path from the activity Id
The other tables look like this:
User Table
userId fName lName
Therapist Table
therapistId therapistFirstName therapistLastName
Activity Table
activityId activityTitle activityPath
So far my query looks like
SELECT
User_Activities.userId,
User_Activities.therapistId,
User_Activities.activityId,
Activities.activityTitle,
Activities.activityPath,
Users.fName,
users.lName,
Therapists.therapistFirstName,
Therapists.therapistLastName
FROM
User_Activities
INNER JOIN Users
ON User_Activities.userId = Users.userId
INNER JOIN Therapists ON
User_Activities.therapistId = Therapists.therapistId
INNER JOIN Activities ON
Activities.activityId = User_Activities.userActivityId
WHERE
User_Activities.userId = 1;
When I run this query It only returns 1 row as a result. However there are two activities in the User_Activites table assigned to userId 1.
If I change : INNER JOIN Activities ON
Activities.activityId = User_Activities.userActivityId
from an INNER JOIN to the LEFT JOIN it will display the second row, however the activityTitle and activityPath will be displayed as NULL in the second row.
userActivityId userId therapistId activityId activityId activityTitle activityPath fName lName therapistFirstName therapistLastName
1 1 1 1 1 Brain GZZ0zpUQ S C M D
11 1 1 1 NULL NULL NULL S C M D
You have pretty much answered your question. The second activity does not have a valid ActivityId.
If you want all activities for a user, then you should phrase the query as:
SELECT . . .
FROM Users u LEFT JOIN
User_Activities ua
ON ua.userId = u.userId LEFT JOIN
Therapists t
ON ua.therapistId = t.therapistId LEFT JOIN
Activities a
ON a.activityId = ua.userActivityId
WHERE u.userId = 1;
You want to start with the table where you want to keep all the rows. Then use LEFT JOIN to bring in other tables.
Two other changes of note:
Table aliases are used to simplify reading and writing the query. The SELECT needs to change to use the aliases.
The WHERE clause refers to the Users table rather than UserActivities.

fetch data from multiple tables in mysql

I have 3 tables named user,fruits,fruits_like.
user table has id,name,email etc fields.
fruits table has id,user_id,name etc fields.
fruits_like table has id,fruit_id and user_id fields.
Now i want to retrieve fruit details from fruits including count for fruit by user_id.
I tried below query but in that i only receive fruits which is liked by $user_id. I need to retrieve all fruits by $user_id.
SELECT f.id, f.date_of_eating, f.healthiness, f.comment,
f.picture, u.user_name,count(l.id) as isLiked
FROM fruit f
LEFT JOIN user u ON f.user_id = u.id
LEFT JOIN fruit_like l on f.id = l.food_id
WHERE f.user_id = '$user_id' and l.user_id=''$user_id''
If i run this query i get all records that i want but i need to include like count for that fruit which i am not able to add in this query.
SELECT f.id, f.date_of_eating, f.healthiness, f.comment, f.picture,
u.user_name FROM fruit f LEFT JOIN user u ON f.user_id = u.id
where f.user_id = '$user_id'
can any one please help me get this done?
Thanks

MYSQL Join Multiple times on same table

I am trying to pull both owner and editby. Both of those fields are INT. Inside a simple table, for example:
users:
user_id user_name
-----------------
2 johnny
3 mecca
doc:
owner content editby
----------------------
2 misc 3
SQL:
SELECT doc.owner, doc.content, doc.editby, users.user_name
FROM doc
LEFT JOIN
users
ON
users.user_id = doc.owner
WHERE
doc_id = $id
I can grab owner user_name, but I am not sure how to obtain editby on the same table. How do I go about pulling the different user names for different id fields multiple times?
Join the users table twice with different aliases
SELECT doc.owner, doc.content,
e.user_name as editor,
o.user_name as owner
FROM doc
LEFT JOIN users o ON o.user_id = doc.owner
LEFT JOIN users e ON e.user_id = doc.editby
WHERE doc_id = $id

How to select users without specific one to many rows in MySQL

Consider the following data set:
users table:
id (int) email (string)
1 first#example.com
2 second#example.com
order_items table:
id (int) user_id (int) generation (string)
1 1 '11'
2 1 '12'
2 1 '12.50'
3 1 '16.00'
4 2 '11'
5 2 '12'
UPDATED question
How can I select users which doesn't have order_items with generation 16.00 and have at least one order_item?
So:
email
second#example.com
1) Returning Users who don't have order item with generation 16 included users with no orders at all.
Assuming you have some kind of id column in order_items table:
select u.* from users u
left outer join order_items oi on (u.id = oi.user_id and oi.generation = 16)
where oi.id is null;
Otherwise use whatever primary key you have in order_items in the where condition to be NULL.
Updated to include answer for the question in comment
2) Returning users who don't have order item with generation 16 but have least one order.
select distinct u.* from users u
left outer join order_items oi16 on (u.id = oi.user_id and oi.generation = 16)
join order_items oiother on (u.id = oiother.user_id and oiother.generation != 16)
where oi16.id is null;
We do the filtering by using a second (normal) join which only returns users where it finds matching rows from the order_items table.
Here we need the distinct because the second join will multiply your rows depending on how many other orders the user have.
Alternatively you can also do a count or sum like this:
select u.*, count(distinct oiother.id) from users u
left outer join order_items oi16 on (u.id = oi.user_id and oi.generation = 16)
join order_items oiother on (u.id = oiother.user_id and oiother.generation != 16)
where oi16.id is null
group by u.id;
This will give you also how many other order items each returned user have. Or omit the count completely and using group by just to return distinct items.
You can use NOT EXISTS() like this:
SELECT * FROM Users u
WHERE NOT EXISTS(SELECT 1 FROM order_items o
WHERE o.userid = u.id
AND o.generation = 16)
That checks if there is a record for this user with order.generation = 16, and if there isn't it selects him.
Or not in()
SELECT * FROM Users u
WHERE u.id NOT IN(SELECT userid FROM order_items o
WHERE o.generation = 16)
That selects the list of users who have order.generation = 16, and select every id except them.
Following query should give you the desired output:
*update*
changed query as per the new result format in the question
As we want the data only from generation table, join with user table is not needed anymore. Here's the updated query:
select id, generation
from mytable where id not in (
select id from mytable
where generation = 16
group by id
);
Here is the SQL fiddle for it.

Selecting primary keys that do not have foreign keys in another table

For simplification, I have two tables related with one to many using a foreign key, for example:
Users table:
id
name
Actions table:
id
user_id
one user may have many actions or not. I need an sql select that returns users ids that don't have a user_id value in the actions table.
Users Table:
id name
1 John
2 Smith
3 Alice
Actions Table:
id user_id
1 3
2 1
So I need an sql query that returns the user id 2 (Smith) because the foreign key values don't include the id 2
I tried the following SQL, but it returns all users ids:
SELECT users.id from users left join actions on actions.user_id is null
select u.id
from users u
left outer join actions a on a.user_id = u.id
where a.user_id is null
Optimized version would be:
SELECT u.id
FROM users u
LEFT JOIN actions a
ON a.user_id = u.id
AND ISNULL(a.user_id)
SELECT u.id
FROM users u
LEFT JOIN actions a
ON a.user_id = u.id
WHERE a.user_id IS NULL