Missing Data in mysql query, Need conditional statement in inner join - mysql

I have been having issues with missing data when I run the following query.
There are some products which has special price, stored in table oc_product_special and some products has regular price stored in table oc_product.
I figured out that it is only showing data if there is a special price in table oc_product_special. it is omitting any data where there is no special price and only regular price. I am not sure how to fix this problem. How and where i can add conditional statement or something like
if there is a regular price present and no special price then show regular price and 0 for special price.
SELECT
pd.name AS 'Product Name',
p.model AS UPC,
p.quantity AS 'Quantity',
p.price AS 'Regular Price',
ps.price AS 'Special Price',
p.cost AS 'COST',
p.status AS 'Status'
FROM oc_product p
INNER JOIN oc_product_description pd
ON pd.product_id = p.product_id
INNER JOIN oc_product_special ps
ON ps.product_id = p.product_id
INNER JOIN oc_manufacturer m
ON p.manufacturer_id = m.manufacturer_id
INNER JOIN oc_product_to_category p2c
ON p2c.product_id = p.product_id
INNER JOIN oc_category c
ON c.category_id = p2c.category_id
INNER JOIN oc_category_description cd
ON c.category_id = cd.category_id
WHERE
c.category_id = 37 OR c.parent_id = 37
GROUP BY pd.name ORDER BY m.name ASC

Use LEFT JOIN, which will retain records on the left side of the join even if they do not match to anything on the right side:
SELECT COALESCE(pd.name, 'NA') AS 'Product Name',
p.model AS UPC,
p.quantity AS 'Quantity',
p.price AS 'Regular Price',
COALESCE(ps.price, 0.0) AS 'Special Price',
p.cost AS 'COST',
p.status AS 'Status'
FROM oc_product p
LEFT JOIN oc_product_description pd
ON pd.product_id = p.product_id
LEFT JOIN oc_product_special ps
ON ps.product_id = p.product_id
INNER JOIN oc_manufacturer m
ON p.manufacturer_id = m.manufacturer_id
INNER JOIN oc_product_to_category p2c
ON p2c.product_id = p.product_id
INNER JOIN oc_category c
ON c.category_id = p2c.category_id
INNER JOIN oc_category_description cd
ON c.category_id = cd.category_id
WHERE c.category_id = 37 OR
c.parent_id = 37
GROUP BY pd.name
ORDER BY m.name
Explanation:
In a LEFT JOIN, when a record on the left side of the join does not match to anything on the right side, the columns from the right side will all appear as NULL in the result set. I used the COALESCE function in my query, which will conditionally replace the first argument with the second if the former be NULL. In this case, the special price will be replaced with zero if NULL. I also used it with the product name in case names be missing in some cases.

use left join on oc_product_special
SELECT
pd.name AS 'Product Name',
p.model AS UPC,
p.quantity AS 'Quantity',
p.price AS 'Regular Price',
ps.price AS 'Special Price',
p.cost AS 'COST',
p.status AS 'Status'
FROM oc_product p
INNER JOIN oc_product_description pd
ON pd.product_id = p.product_id
LEFT JOIN oc_product_special ps
ON ps.product_id = p.product_id
INNER JOIN oc_manufacturer m
ON p.manufacturer_id = m.manufacturer_id
INNER JOIN oc_product_to_category p2c
ON p2c.product_id = p.product_id
INNER JOIN oc_category c
ON c.category_id = p2c.category_id
INNER JOIN oc_category_description cd
ON c.category_id = cd.category_id
WHERE
c.category_id = 37 OR c.parent_id = 37
GROUP BY pd.name ORDER BY m.name ASC
Inner join si for matching value in you case somethings there aren't match so ..use left join

Related

MySQL join products with category tree even if categories are null

I want to export all products from an Open Cart database with their parent categories.
My tables are:
oc_product_description (product_id, name, language ....)
oc_product (product_id, model, price, status ...)
oc_product_to_category (product_id, category_id)
oc_category (category_id, status ....)
oc_category_description (category_id, name, language_id ...)
Here is my code so far:
select pd.name as 'product', cd3.name as 'cat 1', cd2.name as 'cat 2', cd.name as 'cat 3', p.model, p.price
from oc_product_description pd
join oc_product p on pd.product_id = p.product_id
join oc_product_to_category pc on p.product_id = pc.product_id
join oc_category c on pc.category_id = c.category_id
join oc_category_description cd on c.category_id = cd.category_id
join oc_category c2 on (c.parent_id = c2.category_id)
join oc_category_description cd2 on c.category_id = cd2.category_id
join oc_category c3 on (c2.parent_id = c3.category_id)
join oc_category_description cd3 on c3.category_id = cd3.category_id
where
p.status = 1 AND pd.language_id = 2 AND c.status = 1 AND cd.language_id = 2
AND ((c2.status = 1 AND cd2.language_id = 2) OR c.parent_id = 0)
AND ((c3.status = 1 AND cd3.language_id = 2) OR c2.parent_id = 0)
But the problem is that it doesn't return products with only one or two level categories (c.parent_id = 0 and/or c2.parent_id = 0)
UPDATE
I ended up exporting 3 different files and then merge them... 1st file with all 3 level of categories, 2nd file with 2 level of categories and 3rd file with only one level of category
what's making it null is your 3rd level category. Add condition to your 3rd level category when joining.
join oc_category c3 on (c2.parent_id = c3.category_id and c3.category_id != c.category_id)
complete query
select pd.name as 'product', cd3.name as 'cat 1', cd2.name as 'cat 2', cd.name as 'cat 3', p.model, p.price
from oc_product_description pd
join oc_product p on pd.product_id = p.product_id
join oc_product_to_category pc on p.product_id = pc.product_id
join oc_category c on pc.category_id = c.category_id
join oc_category_description cd on c.category_id = cd.category_id
join oc_category c2 on (c.parent_id = c2.category_id and c2.category_id != c.category_id)
join oc_category_description cd2 on c.category_id = cd2.category_id
join oc_category c3 on (c2.parent_id = c3.category_id and c2.category_id != c.category_id and c3.category_id != c.category_id)
join oc_category_description cd3 on c3.category_id = cd3.category_id
where p.status = 1 AND pd.language_id = 2 AND c.status = 1 AND cd.language_id = 2 AND
((c2.status = 1 AND cd2.language_id = 2) OR c.parent_id IS NULL)
AND ((c3.status = 1 AND cd3.language_id = 2) OR c2.parent_id IS NULL)
Please use left join instead of join I guess
select pd.name as 'product', cd3.name as 'cat 1', cd2.name as 'cat 2', cd.name as 'cat 3', p.model, p.price
from oc_product_description pd
join oc_product p on pd.product_id = p.product_id
join oc_product_to_category pc on p.product_id = pc.product_id
LEFT join oc_category c on pc.category_id = c.category_id
LEFT join oc_category_description cd on c.category_id = cd.category_id
LEFT join oc_category c2 on (c.parent_id = c2.category_id)
LEFT join oc_category_description cd2 on c.category_id = cd2.category_id
LEFT join oc_category c3 on (c2.parent_id = c3.category_id)
LEFT join oc_category_description cd3 on c3.category_id = cd3.category_id
where
p.status = 1
Code beforehand have a little bug:
'cat 2' cd2 have same name with 'cat 1' cd
because in 8 line forgot 2 after first c
betters write c2.category_id = cd2.category_id
complete query
select pd.name as 'product', cd3.name as 'cat 1', cd2.name as 'cat 2', cd.name as 'cat 3', p.model, p.price
from oc_product_description pd
join oc_product p on pd.product_id = p.product_id
join oc_product_to_category pc on p.product_id = pc.product_id
LEFT join oc_category c on pc.category_id = c.category_id
LEFT join oc_category_description cd on c.category_id = cd.category_id
LEFT join oc_category c2 on (c.parent_id = c2.category_id)
LEFT join oc_category_description cd2 on c2.category_id = cd2.category_id
LEFT join oc_category c3 on (c2.parent_id = c3.category_id)
LEFT join oc_category_description cd3 on c3.category_id = cd3.category_id
where
p.status = 1

how to Return productid in this example mysql?

how to Return productid who those filterid equal x and y.
this is select and return table
query :
SELECT p.product_id,pf.filter_id
FROM oc_product p
LEFT JOIN oc_product_filter pf
on p.product_id=pf.product_id
where p.product_id in(96621,97026) and pf.filter_id in (1901,1855 )
group by p.product_id,pf.filter_id
The result of the processing:
product_id filter_id
96621 1855
96621 1901
97026 1901
but i want to get product_id who filter_id=1855 and filter_id=1901.
want to show only product_id=96621 and not return product_id=97026
main query :
SELECT p.product_id
FROM oc_category_path cp
LEFT JOIN oc_product_to_category p2c
ON (cp.category_id = p2c.category_id)
LEFT JOIN oc_product_filter pf
ON (p2c.product_id = pf.product_id)
LEFT JOIN oc_product p
ON (pf.product_id = p.product_id)
LEFT JOIN oc_product_description pd
ON (p.product_id = pd.product_id)
LEFT JOIN oc_product_to_store p2s
ON (p.product_id = p2s.product_id)
WHERE pd.language_id = 2 AND p.status = '1' AND p.date_available <= NOW() AND p2s.store_id = 0
AND cp.path_id = 86125
AND pf.filter_id in(1901,1855)
GROUP BY p.product_id
ORDER BY p.price DESC, p.sort_order
try and test:
1.#GordThompson:
this result
2.#Edward Mendez
this result
Use OR instead of AND clause .
WHERE product_id in () OR filter_id in () OR product_id not in ()
Remove the product_id from your IN clause for 97026. Also remove the group by since there are no aggregating functioning.
SET #product_id = xxx
SET #filter_id = xxx
SELECT p.product_id,pf.filter_id
FROM oc_product p
LEFT JOIN oc_product_filter pf
on p.product_id=pf.product_id
where p.product_id in(#product_id) and pf.filter_id in (filter_id)
#group by p.product_id,pf.filter_id
If you want a list of product_id values that have both filter_id=1901 and filter_id=1855 you can use
SELECT product_id
FROM oc_product_filter
WHERE filter_id IN (1901,1855)
GROUP BY product_id
HAVING COUNT(*) = 2
or, if the table may have more than one instance of a specific filter_id for a given product_id you can use
SELECT t.product_id
FROM
(
SELECT DISTINCT product_id, filter_id
FROM oc_product_filter
) t
WHERE t.filter_id IN (1901,1855)
GROUP BY t.product_id
HAVING COUNT(*) = 2

update field using a subquery with left join and group_concat from another table

I'm using the next code, but it fails and I don't know why.
UPDATE pd
SET pd.meta_categories = x.categories
FROM t_product_description pd
JOIN (
SELECT p.product_id AS productid, GROUP_CONCAT(cd.name SEPARATOR ' ') AS categories
FROM t_product AS p
LEFT JOIN t_product_to_category AS p2c ON (p2c.product_id = p.product_id)
LEFT JOIN t_category_description AS cd ON (cd.category_id = p2c.category_id)
GROUP BY p.product_id
) x ON pd.product_id = x.productid
in mysql the join clause became first, (don't need from ) and the the set clause and
UPDATE t_product_description pd
JOIN (
SELECT p.product_id AS productid, GROUP_CONCAT(cd.name SEPARATOR ' ') AS categories
FROM t_product AS p
LEFT JOIN t_product_to_category AS p2c ON (p2c.product_id = p.product_id)
LEFT JOIN t_category_description AS cd ON (cd.category_id = p2c.category_id)
GROUP BY p.product_id
) x ON pd.product_id = x.productid
SET pd.meta_categories = x.categories

How to do correct inner join over this query?

SELECT p.product_id, p.quantity, p.price, pd.name, pd.description
FROM product AS p
INNER JOIN product_description AS pd ON p.product_id = pd.product_id
WHERE p.product_id = 1 AND pd.landuage_id = 5
In this query, only one condition exists, p.product_id in this case, but the other condition pd.landuage_id does not exist. I want the request to be executed, whether it exists. How to do it ?
It's possible duplicate, but right answer is:
SELECT p.product_id, p.quantity, p.price, pd.name, pd.description
FROM product p
LEFT JOIN product_description pd ON p.product_id = pd.product_id AND pd.language_id = 5
WHERE p.product_id = 1;

How to verify two distinct values belong to a field in MySQL

I have the following MySQL query. As you can see in the last line, it asks for the filter_id to be either 51 or 8.
How can I modify this query to make sure the products that are returned are only products that have BOTH filter IDs.
What I did: I tried adding HAVING COUNT(DISTINCT pf.filter_id) >=2 based on other answers in this forum but it did not help.
SELECT COUNT(DISTINCT p.product_id) AS total
FROM ocb3l_product_to_category p2c
LEFT JOIN ocb3l_product_filter pf ON (p2c.product_id = pf.product_id)
LEFT JOIN ocb3l_product p ON (pf.product_id = p.product_id)
LEFT JOIN ocb3l_product_description pd ON (p.product_id = pd.product_id)
LEFT JOIN ocb3l_product_to_store p2s ON (p.product_id = p2s.product_id)
WHERE pd.language_id = '1'
AND p.status = '1'
AND p.date_available <= NOW()
AND p2s.store_id = '0'
AND p2c.category_id = '146'
AND pf.filter_id IN (51,8)
P.S. This query is used in an OpenCart shop to get the total number of products on the category pages.
The HAVING COUNT(DISTINCT pf.filter_id) >=2 clause will work, if you were to GROUP BY the product_id.
One approach is to use an inline view (derived table) so that this check can be performed for each product_id. The result from that can be joined to the other tables.
For example:
SELECT COUNT(DISTINCT fp.product_id) AS total
FROM (
SELECT p.product_id
FROM ocb3l_product p
JOIN ocb3l_product_filter pf
ON pf.product_id = p.product_id
AND pf.filter_id IN (51,8)
WHERE p.status = '1'
AND p.date_available <= NOW()
GROUP BY p.product_id
HAVING COUNT(DISTINCT pf.filter_id) = 2
) fp
JOIN ocb3l_product_to_category p2c
ON p2c.product_id = fp.product_id
AND p2c.category_id = '146'
JOIN ocb3l_product_to_store p2s
ON p2s.product_id = fp.product_id
AND p2s.store_id = '0'
JOIN ocb3l_product_description pd
ON pd.product_id = fp.product_id
AND pd.language_id = '1'
What you need to do is add another JOINed copy of the product_filter table like this:
SELECT COUNT(DISTINCT p.product_id) AS total
FROM ocb3l_product_to_category p2c
LEFT JOIN ocb3l_product_filter pf ON (p2c.product_id = pf.product_id)
LEFT JOIN ocb3l_product_filter pf2 ON (p2c.product_id = pf2.product_id) /*new*/
LEFT JOIN ocb3l_product p ON (pf.product_id = p.product_id)
LEFT JOIN ocb3l_product_description pd ON (p.product_id = pd.product_id)
LEFT JOIN ocb3l_product_to_store p2s ON (p.product_id = p2s.product_id)
WHERE pd.language_id = '1'
AND p.status = '1'
AND p.date_available <= NOW()
AND p2s.store_id = '0'
AND p2c.category_id = '146'
AND pf.filter_id = 51 /*used to be IN (51,8)*/
AND pf2.filter_id = 8 /*new*/