SQL n:m relation - mysql

I have the following tables (unrelated columns left out):
studios:
id | user_id
1 | 1
2 | 1
equipment:
id
1
2
studio_equipment:
id | studio_id | equipment_id
1 | 1 | 1
2 | 1 | 1
I have "studios" and "equipment". A studio belongs to a user. Equipment can be assigned to studios (studio_equipment table). An equipment can be assigned multiple times to a studio but there can also be studios that have no equipment yet.
I want to retrieve all studios for a certain user together with all the possible equipment that could be assigned to these studios. If an equipment has already been assigned to a studio, then show this aswell.
For the example above that would mean the following (for user_id 1):
desired results:
studio.id | equipment.id | studio_equipment.id
1 | 1 | 1
1 | 1 | 2
1 | 2 | null
2 | 1 | null
2 | 2 | null
This is my SQL statement thus far:
SELECT `s`.*, `e`.*, `se`.*
FROM (`studios` AS s)
LEFT JOIN `studio_equipment` AS se ON `s`.`id`=`se`.`studio_id`
LEFT OUTER JOIN `equipment` AS e ON `se`.`equipment_id`=`e`.`id`
WHERE `s`.`user_id` = '1'
But this does not retrieve all the data i want. For Example studio 2 is retrieved but not paired with all the possible equipment.
Thanks in advance for your help!

SELECT
s.id AS studio_id,
e.id AS equipment_id,
se.id AS studio_equipment_id
FROM
studios AS s
CROSS JOIN
equipment AS e
LEFT JOIN
studio_equipment AS se
ON se.studio_id = s.id
AND se.equipment_id = e.id ;

Related

Sql left outer join with three tables

I am developing basically an e-commerce application. Application has two pages (all product and my-basket) authenticated user can add product to own basket. and I have three tables, the tables contains following data. I want to if the user adds product to own basket, these products don't exist on this user's all product page.
How should be the SQL query? I am looking query for all product page. so query's return type must be Product.
If user added any products to own basket on all product page these products
shouldn't see on the all product page for this user.
PRODUCT TABLE
+-------+--------+
| id | name |
+-------+--------+
| 1 | p1 |
| 2 | p2 |
+-------+--------+
USER TABLE
+-------+--------+
| id | name |
+-------+--------+
| 3 | U1 |
| 4 | U2 |
+-------+--------+
BASKET TABLE
+-------+---------+-------------+
| id | fk_user | fk_product |
+-------+---------+-------------+
| 5 | 3 | 1 |
| 6 | 4 | 2 |
+-------+---------+-------------+
So if authenticated user's id is 3. The user should see p2 product on own all product page.
try this:
SELECT product.name
FROM product
LEFT JOIN basket ON basket.fk_product = product.id
WHERE (basket.fk_user != 3 OR basket.fk_user IS NULL)
Check my demo query
If you want you can also join the user table but with the data you gave me is not necessary.
A left join keeps all rows in the first (product) table plus all rows in the second (basket) table, when the on clause evaluates to true.
When the on clause evaluates to false or NULL, the left join still keeps all rows in the first table with NULL values for the second table.
or, more commonly...
SELECT p.name
FROM product p
LEFT JOIN basket b
on b.fk_product = p.id
AND b.fk_user = 3
WHERE b.fk_user is null
What you are describing sounds like NOT EXISTS:
SELECT p.name
FROM product p
WHERE NOT EXISTS (SELECT 1
FROM basket b
WHERE b.fk_product = f.id AND
b.fk_user = 3
);
This seems like the most direct interpretation of your question.

MySQL left join count not showing all entries from left table

I have two tables: vcases(id,statusCategoryID,userID) and vstatuses(id,category).
I'm trying to display a dashboard where user can see number of cases they submitted under each category.
I tried left join but I'm not getting all the category names for a particular user.
This is what I'm doing:
SELECT vs.name as `catName`
, COUNT(vs.name) as `count`
FROM vstatuses vs
LEFT
JOIN vcases v
ON vs.id = v.statusCategoryID
WHERE v.userID = 2
GROUP
BY vs.names
ORDER
BY vs.id
I want to display like this
+----------------------------------------+
| Category | Submitted | Opened | Solved |
| Count | 3 | 1 | 0 |
+----------------------------------------+
But I'm getting this
+-------------------------------+
| Category | Submitted | Opened |
| Count | 3 | 1 |
+-------------------------------+
I want to include the categoryName even if there is no case under that category.
The filter should be with the ON clause
LEFT JOIN vcases v ON vs.id=v.statusCategory AND v.userID = 2
Otherwise it's as if it's an INNER JOIN

How to join more than 2 tables in MySQL?

I have 3 tables i want to join all tables each other. But my 3rd table not working.
See my table -
users
id | username |is_active
----------|----------------|------------
1 | chinu | 1
2 | sradhanjali | 1
3 | User3 | 0
settings
id | user_id | public_msg_notification
----------|-----------|---------------------------
1 | 1 | 1
2 | 2 | 1
3 | 3 | 1
friends
id | user_id | friend_id | is_block
----------|-----------|---------------------------
1 | 3 | 1 | 0
2 | 1 | 2 | 1
3 | 3 | 2 | 0
Query
SELECT a.username FROM users a
JOIN settings b
JOIN friends c ON(a.id=c.user_id OR a.id=c.friend_id)
WHERE a.username IN('john','piter','rahul','sradhanjali')
AND a.id != '1' AND a.is_active=1
AND a.id=b.user_id AND b.public_msg_notification=1
AND c.is_block=0 GROUP BY a.username
I have run this query in my local only sradhanjali username fetched. But this user is_block=1 in the friends table.
I think My third table friends not working. I want to show that result those usernmes where is_block=0. In above data my output should be zero(0) But I am getting 1 record while execute above query.
We had a chat discussion and I think this question is not meant to be on SO for the most part. I did promise if I could figure it out I would try to provide some insight. At this point I think this is a correct approach, but it is very specific to this instance.
SELECT u.username FROM users u
JOIN (SELECT
IF(u.id=f.user_id, f.friend_id, f.user_id) as ids
FROM users u
JOIN friends f ON (f.user_id=u.id OR f.friend_id=u.id)
WHERE
u.id=$SOME_ID AND f.is_block=0) friends ON (u.id=friends.ids)
JOIN settings s ON (s.user_id=friends.ids)
WHERE s.public_msg_notification=1 AND u.is_active=1
GROUP BY friends.ids
By trying to be too specific you aren't able to open up the query any more and have to do a nested query inside. This should get all users you are friends with THEN see which users are accepting public notifications and are active. I'm fearing this will fail. But this at the least will put you in the right direction.

Mysql SELECT display only 1 result instead of multiple from 3 tables

I try to make one SQL request where I get all data from multiple tables. Problem start when one user have for example more "enforcement". But first lets look on code:
SELECT c.id, c.firstname, c.surname, c.email, c.process, c.search_work, c.note,
MAX(CASE WHEN cl.languageID = 1 THEN cl.skill ELSE '-' END)AS 'en',
MAX(CASE WHEN cl.languageID = 2 THEN cl.skill ELSE '-' END)AS 'ge',
ce.enforcement
FROM candidates AS c
LEFT JOIN candidates_language AS cl ON c.id = cl.candidates_id
LEFT JOIN candidates_enforcement as ce on c.id = ce.candidates_id
GROUP BY c.id, c.firstname, c.surname, c.email
As you can see from here I search above multiple tables with using foreign key on candidates ID.
For this purpouse here is how 2 tables looks like:
candidates
------------------------------------------------------------------------
| id | firstname | surname | email |
------------------------------------------------------------------------
| 22 | John | Doe | john#doe.com |
------------------------------------------------------------------------
| 23 | Peter | Miller | doe#john.com |
------------------------------------------------------------------------
candidates_enforcement
--------------------------------------------------
| id | candidates_id | enforcement |
--------------------------------------------------
| 1 | 22 | Advocate |
--------------------------------------------------
| 2 | 22 | Programmer |
--------------------------------------------------
| 3 | 23 | IT Admin |
--------------------------------------------------
candidates_id = foreign key from candidates. With my SQL request above result should looks like:
---------------------------------------------------------------------------------
| id | firstname | surname | email | enforcement
---------------------------------------------------------------------------------
| 22 | John | Doe | john#doe.com | Advocate, Programmer |
---------------------------------------------------------------------------------
| 23 | Peter | Miller | doe#john.com | IT Admin
---------------------------------------------------------------------------------
Unfortunately it display me ALWAYS only 1 result from "enforcement". So for cancidate with id 22 it is Advocate not Advocate, Programmer
Is there a chance someone can help me to find a way how to fix this?
Thanks
p.s. Working demo on FIDDLE
http://sqlfiddle.com/#!9/25b1b/1
You could use GROUP_CONCAT like this:
SELECT
candidates.id,
candidates.firstname,
candidates.surname,
candidates.email,
group_concat(DISTINCT candidates_enforcement.enforcement)
FROM
candidates
LEFT JOIN candidates_enforcement
ON candidates.id = candidates_enforcement.candidates_id
GROUP BY
candidates.id,
candidates.firstname,
candidates.surname,
candidates.email
Reference:
GROUP_CONCAT(expr)
You can use Group_Concat with the Distinct option
SELECT c.id,c.firstname,c.surname,c.email,group_concat(distinct ce.enforcement)
FROM candidates c
LEFT JOIN candidates_enforcement ce
ON c.id=ce.candidates_id
GROUP BY c.id,c.firstname,c.surname,c.email
The distinct option will help you remove off the redundant values.
As I understood you want both enforcement to show up when a person has two enforcement. The problem here is you are LEFT joining the candidates_enforcement table to candidate table.
LEFT join does is get the tuples from candidate table and joins the corresponding tuples from candidates_enforcement. There is only one tuple for candidate in candidate table. So it only shows up one time whether candidates_enforcement has many tuples for that particular candidate or not.
To correct this do a RIGHT JOIN. Or you can do the same LEFT JOIN, with tables swapped.
SELECT c.id, c.firstname, c.surname, c.email,ce.enforcement
FROM candidates AS c
RIGHT JOIN candidates_enforcement as ce on c.id = ce.candidates_id

Select all if no subset is present, otherwise select subset

Ok here's my problem. Assume a customer has access to a number of regions defined in a CustomerRegions table:
CustomerRegionID | CustomerID | RegionID
----------------------------------------
1 | 1 | 1
2 | 1 | 2
Assume that customer 1 has three users 1, 2, and 3. For each user we can specify to which of the CustomerRegions they have access via a table UserRegions:
UserRegionID | UserID | CustomerRegionID
----------------------------------------
1 | 1 | 1
2 | 1 | 2
3 | 2 | 2
So user 1 will have access to both Customerregions and user 2 will only have access to CustomerRegion 2.
If there are UserRegions specified for a given user then only those CustomerRegions are present in the result set, but if no UserRegions are specified for a given user then all CustomerRegions are present in the result. I want to get all accessible regions per user of a given customer. The result I am looking for is something like this:
CustomerID | UserID | RegionID
------------------------------
1 | 1 | 1
1 | 1 | 2
1 | 2 | 2
1 | 3 | 1
1 | 3 | 2
My question is can this be done in a single query and how?
Edit:
I seem to have it working now:
SELECT CustomerID,
UserID,
RegionID
FROM users
LEFT JOIN customerregions ON customerregions.CustomerID = users.CustomerID
LEFT JOIN userregions ON userregions.UserID = users.UserID AND userregions.CustomerRegionID = customerregions.CustomerRegionID
LEFT JOIN regions ON regions.RegionID = customerregions.RegionID
WHERE (userregions.UserID IS NOT NULL
OR (SELECT COUNT(1) FROM userregions WHERE userregions.UserID = users.UserID) = 0)
AND CustomerID = 1
The extra count query in the where seems to do the trick. Thanks #Pablo Martinez for your help. However if someone knows of a better way to do this please let me know.
I'm aggre with #diEcho, the table structure is very confusing
have you try to do a join?
Select CustomerID, UserID, RegionID
from UserRegions join CustomerRegion
on CustomerRegion.CustomerRegionID=UserRegions.CustomerRegionID
where customerID=1