How Can I join multiple tables with information i want? - mysql

I'm using mysql 8.0.31 version.
Below is my database schema ERD.
I want to get inforamtion about products from my DB.
Below is my sql raw query.
SELECT
p.id, p.name, sc.name sub_category, c.name category, count(po.color_id) color_count
FROM products p
INNER JOIN sub_categories sc
ON sc.id = p.sub_category_id
INNER JOIN categories c
ON sc.category_id = c.id
LEFT JOIN products_options po
ON po.product_id = p.id
INNER JOIN genders g
ON po.gender_id = g.id
WHERE c.id = 1
GROUP BY p.id
ORDER BY p.id ASC;
I want to join products table with sub_categories, categories to get categories information about my products AND products table with products_options, colors, genders to get color_count about a product and gender type about a product.
So I wanted to query like this added g.type (gender type information for a product)
SELECT
p.id, p.name, sc.name sub_category, c.name category, count(po.color_id) color_count, g.type
FROM products p
INNER JOIN sub_categories sc
ON sc.id = p.sub_category_id
INNER JOIN categories c
ON sc.category_id = c.id
LEFT JOIN products_options po
ON po.product_id = p.id
INNER JOIN genders g
ON po.gender_id = g.id
WHERE c.id = 1
GROUP BY p.id
ORDER BY p.id ASC;
But this occurs error like this
SQL Error [1055] [42000]: Expression #6 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'mydb.g.type' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
I think this error occurs cuz I didn't use aggregate function for g.type.
Below is my result except g.type in sql select field.
I want to get genders.type field together.
I think I need to sub query and join that table created by sub query. But I don' t know well How can I implement that method.
To combine this gender type information, How can I modify my sql query?
I tried multiple method sql queries in various ways to join table.

You need to either remove the column from select list like:
SELECT p.id, count(po.color_id) color_count
FROM products p
INNER JOIN sub_categories sc
ON sc.id = p.sub_category_i`enter code here`d
INNER JOIN categories c
ON sc.category_id = c.id
LEFT JOIN products_options po
ON po.product_id = p.id
INNER JOIN genders g
ON po.gender_id = g.id
WHERE c.id = 1
GROUP BY p.id
ORDER BY p.id ASC;
or add in group by clause the select columns like:
SELECT p.id, p.name, sc.name sub_category, c.name category, count(po.color_id) color_count, g.type
FROM products p
INNER JOIN sub_categories sc
ON sc.id = p.sub_category_id
INNER JOIN categories c
ON sc.category_id = c.id
LEFT JOIN products_options po
ON po.product_id = p.id
INNER JOIN genders g
ON po.gender_id = g.id
WHERE c.id = 1
GROUP BY p.id,p.name, sc.name sub_category, c.name category, g.type
ORDER BY p.id ASC;

Related

How to do GROUP BY and COUNT(*) in JOIN MySQL

I have tables named company, product, purchase_order, skid, process_record and I want MySQL query result as below.
I tried
SELECT s.id as skidId, s.skidBarcode, po.poNumber, s.companyId, c.companyName, p.productId , p.productName, totalProcessed
FROM skid s
INNER JOIN company c ON s.companyId = c.id
INNER JOIN purchase_order po on s.purchaseOrderId = po.id
INNER JOIN product prdct on p.productId = prdct.id
LEFT JOIN (SELECT skidID, productId , COUNT(*) as processedQuantity FROM process_record GROUP BY productId ) p ON p.skidID= s.id
WHERE s.status = 'closed' ORDER By s.companyId,s.id
However, this query result gives processedQuantity count NULL and random wrong count on some rows.
How can I get the desired MySQL query output as shown in screenshot?
I added GROUP BY skidID, productId instead of GROUP BY productId and it resolved the issue.
SELECT s.id as skidId, s.skidBarcode, po.poNumber, s.companyId, c.companyName, p.productId , p.productName, totalProcessed
FROM skid s
LEFT JOIN (SELECT skidID, productId , COUNT(*) as processedQuantity FROM process_record GROUP BY skidID, productId ) p ON p.skidID= s.id
INNER JOIN company c ON s.companyId = c.id
INNER JOIN purchase_order po on s.purchaseOrderId = po.id
INNER JOIN product prdct on p.productId = prdct.id
WHERE s.status = 'closed' ORDER By s.companyId,s.id

I need empty fields in multitable query

This should be easy for you, but I'm lost here:
I have a database with 4 tables: orders, clients, products, orders_products
I need to fetch all clients, with all of their orders, including the ones that don't have any order.
I'm only getting the ones that have made an order. Poor old "Nick" in the Clients table won't show up.
What am I doing wrong here?
SELECT c.name clientname, o.id orderID, GROUP_CONCAT(p.name) productNAMEs,
GROUP_CONCAT(p.id) productIDs
FROM clients c, orders o, orders_products op, products p
WHERE c.id = o.client_id
AND c.status = 1
AND o.id = op.order_id
AND p.id = op.product_id
GROUP BY c.name
See table definitions here:
https://www.db-fiddle.com/f/bTRSLfYTa19S2EpE2zKwUv/7
Update
#scaisedge came up with an answer that includes clients without orders:
SELECT c.name clientname, o.id orderID, GROUP_CONCAT(p.name) productNAMEs,
GROUP_CONCAT(p.id) productIDs
FROM clients c
LEFT JOIN orders o ON c.id = o.client_id
LEFT JOIN orders_products op ON o.id = op.order_id
LEFT JOIN products p ON p.id = op.product_id
WHERE c.status = 1
GROUP BY c.name
You can see the results here: https://www.db-fiddle.com/f/8bGcQJSbSFmKMUo1tLuZuA/1
It seems that not using JOINs was my problem.
Use explicit join sintax and left join for retrive also row that don't match
SELECT c.name clientname, o.id orderID, GROUP_CONCAT(p.name) productNAMEs,
GROUP_CONCAT(p.id) productIDs
FROM clients c
LEFT JOIN orders o ON c.id = o.client_id
LEFT JOIN orders_products op ON o.id = op.order_id
LEFT JOIN products p ON p.id = op.product_id
WHERE c.status = 1
GROUP BY c.name
I recommand you to use JOIN's to UNIFY the tables data. A JOIN clause is used to combine rows from two or more tables, based on a related column between them.
https://www.w3schools.com/sql/sql_join.asp
SELECT *
FROM clients LEFT JOIN orders ON clients.id = orders.client_id
LEFT JOIN orders_products ON clients.id = orders_products.order_id
LEFT JOIN products ON products.id = orders_products.product_id
WHERE clients.status = 1;
Never use commas in the FROM clause. Always use proper, explicit, standard JOIN syntax.
Also, your GROUP BY needs to match the unaggregated columns in the SELECT.
I'm not sure if you intend this:
SELECT c.name as clientname, o.id as orderID,
GROUP_CONCAT(p.name) as productNAMEs,
GROUP_CONCAT(p.id) productIDs
FROM clients c left join
orders o
on c.id = o.client_id left join
orders_products op
on o.id = op.order_id left join
products p
on p.id = op.product_id
WHERE c.status = 1
GROUP BY c.name, o.id;
Or:
SELECT c.name as clientname,
GROUP_CONCAT(p.name) as productNAMEs,
GROUP_CONCAT(p.id) productIDs
FROM clients c left join
orders o
on c.id = o.client_id left join
orders_products op
on o.id = op.order_id left join
products p
on p.id = op.product_id
WHERE c.status = 1
GROUP BY c.name;

MySQL - #1066 - Not unique table/alias: 'components' with multiple inner joins

I have this query and I am getting error #1066 - Not unique table/alias: 'components'. What seems to be the issue?
SELECT COUNT(*) FROM `products`, `components`, `tradeNames`
INNER JOIN `componentsMap` ON componentsMap.product_id = product.id
INNER JOIN `components` ON componentsMap.component_id = components.id
INNER JOIN `tradeNamesMap` ON .tradeNamesMap.product_id = products.id
INNER JOIN `tradeNames` ON tradeNamesMap.tradeName_id = tradeNames.id
WHERE (((((LOWER(inci) LIKE '%abies%')
OR (trade_name.LOWER(name) LIKE '%abies%'))
OR (components.LOWER(no_cas)='abies'))
OR (components.LOWER(no_einecs)='abies'))
OR (components.LOWER(name)='abies'))
AND (`published`=1)
ORDER BY `trade_name`.`name` DESC
You don't need to list the tables before the INNER JOINs. In fact, simply don't ever use commas in the FROM clause. So:
SELECT COUNT(*)
FROM `products`
INNER JOIN `componentsMap` ON componentsMap.product_id = product.id
INNER JOIN `components` ON componentsMap.component_id = components.id
INNER JOIN `tradeNamesMap` ON tradeNamesMap.product_id = products.id
INNER JOIN `tradeNames` ON tradeNamesMap.tradeName_id = tradeNames.id
WHERE (((((LOWER(inci) LIKE '%abies%')
OR (trade_name.LOWER(name) LIKE '%abies%'))
OR (components.LOWER(no_cas)='abies'))
OR (components.LOWER(no_einecs)='abies'))
OR (components.LOWER(name)='abies'))
AND (`published`=1)
ORDER BY `trade_name`.`name` DESC;
The above query only returns one row because of the COUNT(). The order by suggests that you actually want this information for each trade_name.name. If so, you need a GROUP BY:
SELECT tn.name, COUNT(*)
FROM `products` p INNER JOIN
`componentsMap cm
ON cm.product_id = p.id INNER JOIN
`components` c
ON cm.component_id = c.id INNER JOIN
`tradeNamesMap` tnm
ON tnm.product_id = p.id INNER JOIN
`tradeNames` tn
ON tnm.tradeName_id = tn.id
WHERE ((LOWER(inci) LIKE '%abies%') OR
(tn.LOWER(name) LIKE '%abies%') OR
(c.LOWER(no_cas)='abies') OR
(c.LOWER(no_einecs)='abies') OR
(c.LOWER(name)='abies')
) AND
(`published` = 1)
GROUP BY tn.name
ORDER BY tn.`name` DESC
INNER JOIN `[components]` ON componentsMap.component_id = components.id
AND
SELECT COUNT(*) FROM `products`, [`components`], `tradeNames`
Two components are there.
Just guessing, and untested, but I suspect that something like this would do what you're after...
SELECT n.name
, COUNT(*)
FROM products p
JOIN componentsMap pc
ON pc.product_id = p.id
JOIN components c
ON c.id = pc.component_id
JOIN tradeNamesMap pn
ON pn.product_id = p.id
JOIN tradeNames n
ON n.id = pn.tradeName_id
WHERE
( inci LIKE '%abies%'
OR n.name LIKE '%abies%'
OR 'abies' IN (c.no_cas,c.no_einecs,c.name)
)
AND published = 1
GROUP
BY n.name
ORDER
BY n.name DESC

How to use Group by in mysql

I'm using this sql query to get the product list from DB.
SELECT distinct P.product_id, B.brand_name, P.product_name, P.product_description, SC.sub_category_name, P.product_image_path
FROM table_products as P
INNER JOIN table_brands as B
ON P.brand_id = B.brand_id
INNER JOIN table_product_categories as PC
ON P.product_id = PC.product_id
INNER JOIN table_subcategories as SC
ON SC.sub_categories_id = PC.category_id
INNER JOIN table_subcategory_categories as SCC
ON SC.sub_categories_id = SCC.subcategory_id
ORDER BY P.product_id DESC";
It works fine for me. But when same product is in multiple subcategories. It gives me a new row. I just wanted to avoid this and wants GROUP by with SC.sub_category_name. So when a product is in multiple categories, all the categories should list in same row.
Current
853 Tops Premium Vermicelli /images/tops/853.png Noodles
853 Tops Premium Vermicelli /images/tops/853.png Vermicelli
Expecting
853 Tops Premium Vermicelli /images/tops/853.png Noodles, Vermicelli
You can use GROUP_CONCAT() for that purpose, grouping by SC.sub_category_name and remove the distinct. Something like
SELECT P.product_id,
B.brand_name,
P.product_name,
P.product_description,
GROUP_CONCAT(SC.sub_category_name) as sub_cat_list,
P.product_image_path
FROM table_products P
INNER JOIN table_brands B
ON P.brand_id = B.brand_id
INNER JOIN table_product_categories PC
ON P.product_id = PC.product_id
INNER JOIN table_subcategories SC
ON SC.sub_categories_id = PC.category_id
INNER JOIN table_subcategory_categories SCC
ON SC.sub_categories_id = SCC.subcategory_id
GROUP BY P.product_id
ORDER BY P.product_id DESC;

How to remove a row if sub query returns null value?

I have following query.
select
Product.*,
(
select
group_concat(features.feature_image order by product_features.feature_order)
from product_features
inner join features
on features.id = product_features.feature_id
where
product_features.product_id = Product.id
and product_features.feature_id in(1)
) feature_image
from products as Product
where
Product.main_product_id=1
and Product.product_category_id='1'
I want to bypass the row if feature_image is empty.
Your query looks a bit strange because you are doing most of the work in a subquery:
select p.*, (select group_concat(f.feature_image order by pf.feature_order)
from product_features pf inner join
features f
on f.id = pf.feature_id
where pf.product_id = p.id and pf.feature_id in (1)
) as feature_image
from products p
where p.main_product_id=1 and p.product_category_id='1';
A more common way to phrase the query is as an inner join in the outer query:
select p.*, group_concat(f.feature_image order by pf.feature_order) as feature_image
from products p join
product_features pf
on pf.product_id = p.id and pf.feature_id in (1) join
features f
on f.id = pf.feature_id
where p.main_product_id=1 and p.product_category_id='1'
group by p.id;
This will automatically include only products that have matching features. You would use left outer join to get all products.