1:n relationship and sql query - mysql

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

Related

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

select names that is equal to the id of other tables - SQL

I have two tables products and categories. For products I have the ff fields:
id
pname
category_id
date
And for the cateogries id I have:
id
name
So using inner join I am trying to select all the names of categories that are equal to the category_id inside the products table.
Here's my take:
SELECT
c.name
FROM
categories AS c
INNER JOIN products AS p ON c.id = p.category_id
However this one did not work out and it's just sending me an empty array.
Any idea how can I do this? thanks!
If you just want category names, then exists or in is more appropriate than join:
SELECT c.name
FROM categories c
WHERE EXISTS (SELECT 1 FROM products p WHERE c.id = p.category_id);
You will not have to worry about eliminating duplicates, unless two categories have the same name.
This is also much more efficient than using SELECT DISTINCT on your query, especially if products has an index where category_id is the first key.

Multi joined MySQL query has an issue

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;

Query Topics & Categories from multiple tables

I'm having an issue with MySQL. I have two tables, categories and topics. I want to select all of the categories and join topics where categories.id equals the max topics.id where topics.cat_id equals categories.id. Basically I am trying to show a list of categories and then the most recent topic under that category.
Here is my select statement so far:
SELECT
*
FROM
categories
LEFT JOIN
topics
ON
categories.cat_id = (SELECT
MAX(topics.id), topic_cat
FROM
topics
WHERE
topic_cat = categories.cat_id)
GROUP BY
categories.cat_id
How can I efficiently do that? I'm getting an error "Operand should contain 1 column(s)".
You should consider updating your select clause to only pull the columns you need from both tables (there will likely be duplicate columns with *), but give this a shot:
select *
from categories c
left join topics t
on c.cat_id = t.topic_cat
and t.id = (select MAX(id) from topics where topic_cat = c.cat_id)

Display categories and their counts

I have two tables in my database (Jobs and Categories), I need help with an SQL that will select the categories and also count the number of jobs in each category. I am using MySQL if that helps.
So far
SELECT * from categories c left join jobs j on (c.job_id = j.job_id);
Thanks
Assuming you have a CategoryName column...
select c.CategoryName,
count(*)
from Categories c
join Jobs j on j.job_id = c.jobID
group by c.CategoryName
Assuming your table structure is similar to this:
Category
ID, Name
Job
ID, CategoryID, Name
SELECT Category.Name, COUNT(Job.ID)
FROM Job
INNER JOIN Category ON Job.CategoryID = Category.ID