MySQL query joining issue while using FIND_IN_SET and GROUP_CONCAT - mysql

So I have a product/categories/brands structure where a products categories are identified by a column containing a comma separated list of category IDs, i.e. 101,105,108, as well as a brand ID column.
I'm trying to get a list of all the products, replace the category IDs with a comma separated list of category names, and also the brand name.
I have the following query that works:
SELECT
productid AS product_id,
prodname AS name,
prodcode AS code,
proddesc AS description,
prodprice AS price,
GROUP_CONCAT(c.catname)
FROM
products p,
categories c
WHERE
FIND_IN_SET(c.categoryid, p.prodcatids)
GROUP BY p.productid
However when I try and left join as follows to also get the brand name, it breaks and says that column p.prodbrandid doesn't exist (it does).
SELECT
productid AS product_id,
prodname AS name,
prodcode AS code,
proddesc AS description,
prodprice AS price,
b.brandname AS brand,
GROUP_CONCAT(c.catname)
FROM
products p,
categories c
LEFT JOIN
brands b ON p.prodbrandid = b.brandid
WHERE
FIND_IN_SET(c.categoryid, p.prodcatids)
GROUP BY p.productid
Any pointers to what I'm missing would be greatly appreciated!

From the advice in the comments:
SELECT
p.productid AS product_id,
p.prodname AS name,
p.prodcode AS code,
p.proddesc AS description,
p.prodprice AS price,
b.brandname AS brand,
GROUP_CONCAT(c.catname)
FROM
products p
INNER JOIN categories c on FIND_IN_SET(c.categoryid, p.prodcatids) > 0
LEFT JOIN brands b ON p.prodbrandid = b.brandid
GROUP BY p.productid
It's not ideal to store data as comma separated lists though; this really should be split out to an additional table that breaks down the many:many relationship between product and category (multiple products can have multiple categories) into two 1:many relationships (a productcategories table, that has a productid,categoryid pair)
Consider something like this as a one time op:
CREATE TABLE ProductCategories(ProductId INT, CategoryId INT)
INSERT INTO ProductCategories
SELECT
p.productid, c.categoryid
FROM
products p
INNER JOIN categories c on FIND_IN_SET(c.categoryid, p.prodcatids) > 0
Then use it going forwards, and drop the categories column

Related

Join Two Tables based on a third table's data

I have 3 tables, for the sake of this exercise we'll call them: Products, Price, and Discount. I'm trying to join Products and Price tables, only if the ProductID is found in Discount.ProductID (ProductID column within the Discount table).
Products:
ProductID
Size
Color
Ref#
A1234
Small
Blu
0C94
B5678
Med
Red
1D96
Price:
Ref#
Base
Tax
0C94
3.48
0.96
Discount:
ProductID
List
Site
A1234
Two
Three
I'm familiar with joins, so my code starts off as:
SELECT * FROM Product as a
left join Price as b
on a.Ref# = b.Ref#
but I've never nested a constraints within a where clause (if that's even the correct approach) based on a third table. Any advice would be greatly appreciated. The end result would be a new products table that only shows the one product, because ProductID B5678 is not in the Discount table.
Just do a 3-table join.
SELECT DISTINCT a.*, b.*
FROM Product AS a
JOIN Price AS b ON a.`Ref#` = b.`Ref#`
JOIN Discount AS c ON a.ProductID = c.ProductID
If you don't need any of the contents of the Discount table, use the exists() funtion to execute a sub query in the where clause. This will give you the fastest results.
SELECT *
FROM Product as a
left join Price as b on a.Ref# = b.Ref#
WHERE EXISTS (
SELECT *
FROM Discount as c
WHERE c.ProductID = a.ProductID
)
If however you do need one or more of the columns of Discount, do an inner join between Product and Discount, joining them on the ProductID. This will result in only the products that have discount, and then do another left join to Price to get the columns from Price into the resultset too. Do be aware though that in case multiple rows exist in Discount for the one Product row, this will result in the same product shown on multiple rows.
SELECT *
FROM Product as a
inner join Discount as c on c.ProductID = a.ProductID
left join Price as b on a.Ref# = b.Ref#

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.

MySQL JOIN two lookups

I have two tables
products
id
code
description
category
subcategory
product_categorys
id
category_name
category_master
Data in products table
1, UK001, Description Text, 1, 2
Data in product_category table
1, Network Cable, 0
2, CAT6, 1
I want to lookup the products and return the category and subcategory i have reserached the best way to do this butt canot get my head around it, i have managed to return one lookup using the following.
SELECT products.product_code, products.description, product_category.category_name, product_category.category_name
FROM products
LEFT JOIN product_category ON product_category.id = products.category AND product_category.ID = products.subcategory
ORDER BY description ASC
Which returns as expected
UK001, Description Text, Network Cables
I also want to return the subcategory, adding another join does not work and this is where i am stuck,
You just need two joins:
SELECT p.product_code, p.description, pc.category_name, pcs.category_name
FROM products p LEFT JOIN
product_category pc
ON pc.id = p.category LEFT JOIN
product_category pcs
ON pcs.ID = p.subcategory
ORDER BY description ASC;
Note also the use of table aliases. These make the query easier to write and to read.

Joining four mySQL tables without a single common value

I have four tables that I need to pull data from. Three of the tables have a common value (product_id) the fourth table has a value in common with the third table (category_id). So they look something like this:
Products:
product_id, name, quantity, image, weight
Product_Description:
product_id, Description
Product_to_Category:
product_id, category_id
Category:
category_id, category_name
I need to pull all of the data and combine it into a result that looks like this
Name, Quantity, Image, Weight, Description, Category name
I know how to do a JOIN that works for the first three tables but I don't know how to add the into the results.
Just add an additional join on the category_id:
select p.name, p.quantity, p.image, p.weight, pd.description, c.category_name
from products p
join product_description pd on p.product_id = pd.product_id
join Product_to_Category pc on p.product_id = pc.product_id
join category c on pc.category_id = c.category_id
A Visual Explanation of SQL Joins

Get only results from table "products" if they have entries in two other tables (identified by ID and product type columns)

I have a table with "products" that stores a product ID and product type (string).
I'd like to retrieve all those "products", joining them to two other tables that list two individual products and ignore all other products that are not found in these two tables. I have the "product_type" inside the "products" table.
Here's a sample structure:
Table products (ID, idProduct, type)
1|3|tv
2|4|tv
3|13|phone
Table tvs (ID, name)
3|Sony
4|Phillips
Table phones (ID, name)
13|Samsung Galaxy
Even if there are duplicate idProduct values in products we are identifying/joining by also checking the type column. Currenly, my approach using LEFT JOIN to both tables does not work correctly, because it doesn't return any values in case proucts contains only one type of product.
I suggest using a union - so you can get data from the other tables rather then just products table:
(SELECT p.ID, p.idProduct, p.type, t.name
FROM products p, tvs t
WHERE p.idProduct=t.ID AND p.type = 'tv')
UNION
(SELECT p.ID, p.idProduct, p.type, t.name
FROM products p, phones t
WHERE p.idProduct=t.ID AND p.type = 'phones')
SELECT * FROM products p
LEFT JOIN tvs tvs ON tvs.id=p.idProduct AND p.type="tv"
LEFT JOIN phones phones on phones.id=p.idProduct AND p.type="phone"
WHERE (tvs.id IS NOT NULL OR phones.id IS NOT NULL)
Self answer, but I think others might find it useful.
The trickyp part is the OR in the WHERE condition. We are doing a LEFT JOIN, but we must also check if the product exists in the first OR second table.