Multi joined MySQL query has an issue - mysql

I have the following query, the job scenario is:
I have three tables. Categories, Roles and Roles_to_categories table.
roles_to_categories table:
--id-- --role_id-- --category_id--
A role in roles table, may be bound to several categories in a pivot table named roles_to_categories. I want a role, for instance admin to fetch all the categories from the table categories which are bound to it in table roles_to_categories.
It works fine, but the problem is when aggregation comes in: GROUP_CONCAT().
I want to just get the list of parent categories, and include their children in a separate column by using GROUP_CONCAT(). My problem is that GROUP_CONCAT() seems to ignore the roles_to_categories pivot table when it retrieves the list of children, which means it includes the children of the a certain category that is NOT ALLOWED (I mean there is no record in roles_to_categories to bind it a role)
The query is:
select categories.name as cat_name, categories.id as cat_id,
roles.name as role_name, roles.id as role_id, roles_to_categories.id as cat_id, roles_to_categories.role_id as role_id,
roles_to_categories.category_id,
group_concat('name: ', categories2.name) as cat_children
FROM roles left join roles_to_categories on roles.id = roles_to_categories.role_id
left join categories on roles_to_categories.category_id = categories.id
left join categories as categories2 on categories2.parent_id = categories.id
WHERE roles.name = "admin";
It selects required columns from all three tables, starting from roles then it left joins to roles_to_categories to get its related records and then re-left-joins on categories table from roles_to_categories to select categories whose ids exists in the fetched records and ....

group_concat is an aggregate - you'll need to group by all non-aggregated columns in your select list.
You've also included multiple aliases of both sides of joined columns in your query - this will be confusing and redundant, and aliased category.id and roles_to_category.id to cat_id.
In this case, since you want to concatenate all children of a parent category, this will be like so:
select
categories.name as cat_name, categories.id as cat_id,
roles.name as role_name, roles.id as role_id,
roles_to_categories.id as roles_to_cat_id,
group_concat('name: ', categories2.name) as cat_children
FROM
roles left join roles_to_categories
on roles.id = roles_to_categories.role_id
left join categories on roles_to_categories.category_id = categories.id
left join categories as categories2 on categories2.parent_id = categories.id
WHERE
roles.name = 'admin'
GROUP BY
categories.name, categories.id, roles.name, roles.id, roles_to_categories.id;

Related

How to get a row count when using relationships in mysql

I'm a newbie with sql and I've managed to select rows with relationship to many tables with the sql below. I now have a forth table with items that are "children" to the model. There is a relation between "id" in the models table (526 rows) and "model_id" in the items table (1505 rows). I would now want to count the items in the items table that have the same model_id as the id in the models table and output them as Items_in_model.
SELECT models.id AS Id, categories.name AS Category, models.category_name
AS CategoryName, manufacturers.name AS Manufacturer, models.model AS Model,
models.day_price AS dayprice, models.week_price AS weekprice
FROM
models, categories, manufacturers
WHERE models.category=categories.id AND
models.manufacturer=manufacturers.id
ORDER BY CategoryName ASC
I got the counting working "standalone" with this sql
SELECT COUNT(items.id) AS Count FROM items WHERE items.model_id
LIKE 2
I've tried many different approaches but this is the only one that didn't give me an error but only outputs one row (of 526) and the count is (1505 as in all items)
SELECT models.id AS Id, categories.name AS Category,
models.category_name AS CategoryName, COUNT(items.id) AS Count,
manufacturers.name AS Manufacturer, models.model AS Model,
COUNT(DISTINCT(items.id)) AS ModelCount, models.day_price AS dayprice,
models.week_price AS weekprice
FROM
models, categories, manufacturers, items
WHERE models.category=categories.id AND
models.manufacturer=manufacturers.id AND models.id=items.model_id
ORDER BY CategoryName ASC
Thanks in advance!
Your goal is not 100% clear, but here is my guess:
SELECT m.id AS Id,
c.name AS Category,
m.category_name AS CategoryName,
manufacturers.name AS Manufacturer,
m.model AS Model,
COUNT(i.id) AS ModelCount,
m.day_price AS dayprice,
m.week_price AS weekprice
FROM models m
LEFT JOIN categories c
ON m.category=c.id
LEFT JOIN manufacturers
ON m.manufacturer=manufacturers.id
LEFT JOIN items i
ON m.id=i.model_id
GROUP BY m.id
UPDATE Not sure about your new question, But I doubt you need extra JOIN. Try this way:
SELECT m.id AS Id,
c.name AS Category,
m.category_name AS CategoryName,
manufacturers.name AS Manufacturer,
m.model AS Model,
COUNT(i.id) AS ModelCount,
SUM(IF(i.reservable = 1,1,0)) AS ModelReservableCount,
m.day_price AS dayprice,
m.week_price AS weekprice
FROM models m
LEFT JOIN categories c
ON m.category=c.id
LEFT JOIN manufacturers
ON m.manufacturer=manufacturers.id
LEFT JOIN items i
ON m.id=i.model_id
GROUP BY m.id

MySQL Query returning same row twice

I am trying to display data using 3 tables
posts
- id
- category_id
- user_authors_id
- title
- status
user_authors
- id
- author_name
categories
- id
- name
subcategories
- id
- name
What I am trying to do is. I am creating a view panel that will display the posts. So, i am using 3 tables. From user_authors I'll get the author name, from categories table I'll get the category name, now the category tables have subcategory id, so I also want to get the subcategory name.
I am having two rows in the posts table with id 29 and 30 but when i run the below query it shows 2 entries with the same data.
SELECT
posts.id,
categories.name AS cat_name,
subcategories.name AS subcat_name,
posts.title,
user_authors.author_name,
posts.created,
posts.status
FROM posts
INNER JOIN user_authors ON (user_authors.id = posts.user_author_id)
INNER JOIN categories ON(posts.category_id = categories.id)
INNER JOIN subcategories ON (categories.id = subcategories.category_id)
But, if I remove this statement INNER JOIN subcategories ON (categories.id = subcategories.category_id) and run the query, it runs perfect, all the rows are shows properly.
What's happening, I am not trying to get it. Where is the query wrong, also it's showing no error.
INNER JOIN subcategories ON (categories.id = subcategories.category_id)
As it is, for your query to return what you expect, there must be one and only one record in subcategories matches the given post :
if more than one subcategory matches a given post, the post line will be duplicated in the results
if no subcategory matches a given post, the post will not appear in the results
Depending on your use case, you want :
not to JOIN subcategory, to avoid duplicating posts
LEFT JOIN subcategory instead of INNER JOIN subcategory to avoid posts without subcategory to be filtered out
If you do have multiple subcategories for a given post and you still want to display a single row in the results, you can use the GROUP_CONCAT aggregate funtion to concatenate the subcategories into one field :
SELECT
posts.id,
categories.name AS cat_name,
GROUP_CONCAT( subcategories.name, ', ') AS subcat_names,
posts.title,
user_authors.author_name,
posts.created,
posts.status
FROM posts
INNER JOIN user_authors ON (user_authors.id = posts.user_author_id)
INNER JOIN categories ON(posts.category_id = categories.id)
LEFT JOIN subcategories ON (categories.id = subcategories.category_id)
GROUP BY
posts.id,
categories.name,
posts.title,
user_authors.author_name,
posts.created,
posts.status

SQL Multiple Joins multiple where

I have three tables is question. categories, vocabulary & tex. I am trying to figure out how to have multiple joins in my query, i thought you can just add as many joins as you wanted, as long as you reference them properly.
So, the following two work perfectly on there own:
1.
SELECT
categories.ID AS ID,
categories.ParentID AS ID,
vocabulary.value AS Name
FROM categories
INNER JOIN vocabulary
ON categories.sid=vocabulary.sid
WHERE vocabulary.langid=1
2.
SELECT
categories.ID AS ID,
categories.ParentID AS ID,
tex.value AS Description
FROM categories
INNER JOIN tex
ON categories.tid=tex.tid
WHERE tex.langid=1
However, if i try to combine them as follows, it does not work.
categories.ID AS ID,
categories.ParentID AS ID,
vocabulary.value AS Name
tex.value AS Description
FROM categories
INNER JOIN tex
ON categories.tid=tex.tid
WHERE tex.langid=1
INNER JOIN vocabulary
ON categories.sid=vocabulary.sid
WHERE vocabulary.langid=1
Any ideas?
Thanks in advance
John
In MySQL, when you have columns with the same name, one of them will only be shown. You need to identify them uniquely by supplying ALIAS. And you can either put the condition on the ON clause or WHERE clause which could yield the same result since it uses INNER JOIN.
SELECT categories.ID AS CategoryID,
categories.ParentID AS CategoryParentID,
vocabulary.value AS Name
tex.value AS Description
FROM categories
INNER JOIN tex
ON categories.tid = tex.tid
INNER JOIN vocabulary
ON categories.sid = vocabulary.sid
WHERE vocabulary.langid = 1 AND
tex.langid = 1

MySQL Left Join Multiple Rows

I have an interesting challenge... I have two tables, products and users.
products contains 2 columns, user_id and current_bidder, which hold two different IDs from the users table.
I would like to select all columns from products, and the name and rating from the users table for each user_id and current_bidder.
Essentially, I'm trying select columns from two different rows on a joined table, while disambiguating their names.
Any help would be greatly appreciated.
Join to the user table twice, and give each copy a different alias. Something like this:
select p.name, p.weight, owner.name, bidder.name
from product p
join user owner
on ...
join user bidder
on ...
The nice way to avoid ambiguity between columns is to add an ALIAS on it.
SELECT a.*, -- selects all records from products
b.name AS user_name, -- user_name is an alias of users.name (user_id)
c.name AS bidder_name -- user_name is an alias of users.name (current_bidder)
FROM products a
LEFT JOIN users b
ON a.user_id = b.id
LEFT JOIN users c
ON a.current_bidder = c.id
The reason why I used LEFT JOIN is because I assumed that some products has no bidder yet. If INNER JOIN was used, product will never be shown on the result until there's a bidder on it.

1:n relationship and sql query

I have two tables
entries(id,name,desc,cat_id)
and
categories(id,name,parent)
entries.cat_id and categories.id are FK and between entries and categories there is a 1:n relationship. So how to get distinct cat_id from entries and its name in categories.
I tried with
SELECT DISTINCT
entries.cat_id
FROM entries
JOIN categories ON categories.id = entries.cat_id
but I get only cat_id as result but I want categories name also. Where is my mistake? Thank You in advance.
SELECT DISTINCT
cat_id, categories.name
FROM entries JOIN categories ON categories.id = entries.cat_id
Simply add the column you want to your select:
SELECT DISTINCT entries.cat_id
categories.name
FROM entries
JOIN categories ON categories.id = entries.cat_id