Just when I thought I had figured out MySQL JoINS I run into this and it's doing my head in..
I've three tables for a shop:
tblProducts tblProdCat tblCategory
prodID prodCatID categoryID
prodName categoryID categoryHidden
prodPrice prodID categoryName
And what i'd like to do is create a query that finds products in a category that aren't hidden and I cannot get this to work.
At present all I can do is find the products in a category by joining the products table to the ProdCat table. As this query works I adapted it to this:
SELECT
p.prodID, p.name,
FROM
tblProducts p
INNER JOIN
tblProdCat pc
ON
pc.prodID = p.prodID
inner JOIN
tblCategory c
ON
c.categoryID = pc.categoryID
WHERE
pc.categoryID = '7' AND
c.categoryHidden = '0'
Can anybody help me identify why this isn't working?
edit: fixed the name of prodID (it was a typo and not what is causing the issue)
You do not have a column called productID on tblProducts
try
SELECT p.prodID, p.name,
FROM tblProducts p
INNER JOIN tblProdCat pc
ON pc.productID = p.prodID
inner JOIN tblCategory c
ON c.categoryID = pc.categoryID
WHERE pc.categoryID = '7' AND c.categoryHidden = '0'
Also I can not tell from your schema but if pc.categoryID is a number then you do not need quotes.
select * from tblProducts as p Inner join tblProdCat as pc Inner join tblCategory as c
where pc.categoryID = '7' AND c.categoryHidden = '0'
try this way
Try something like this (just dummy code )
select p.productID, p.name from
tblProducts as p,tblCategory as c,tblProdCat as pc
where pc.categoryID = '7' AND c.categoryHidden = '0'
Related
I am using this database query in my CodeIgniter model.
SELECT
p.product_id,
p.product_name,
p.product_photo,
p.size,
p.price,
p.status,
p.product_image_path
FROM
products AS p
LEFT JOIN
product_category AS pc
ON
p.product_id = pc.product_id
LEFT JOIN
vendor_products AS vp
ON
vp.product_id = pc.product_id
WHERE
pc.category_id = 2
AND
vp.vendor_id = 36
AND
pc.subcategory_id IN (1,2)
AND
pc.subcategory_value_id IN (1,4)
And it returning me:
I want those products only who fills all conditions of sub_category_value_id. Now it is returning all the conditions.
I am new to database and don't know much about queries.
Below query will give you distinct products with product_id and product_name on basis of given vendor_id, category_id, subcategory_id's and subcategory_value_id's.
Let me know if this works for you!
SELECT
DISTINCT p.product_id,
p.product_name
FROM products AS p
LEFT JOIN product_category AS pc ON p.product_id = pc.product_id
LEFT JOIN vendor_products AS vp ON p.product_id = vp.product_id
LEFT JOIN subcategories AS sc ON sc.subcategory_id = pc.subcategory_id
LEFT JOIN subcategories_value AS scv ON scv.subcategory_value_id = pc.subcategory_value_id
WHERE vp.vendor_id = 2
AND vp.category_id = 2
AND pc.subcategory_id IN (1, 2)
AND scv.subcategory_value_id IN (1, 4)
ORDER BY p.product_id;
It seems like you shouldn't use left join to product_category table. The LEFT JOIN keyword returns all records from the left table (product_category) Please try like below:
SELECT
p.product_id,
p.product_name,
p.product_photo,
p.size,
p.price,
p.status,
p.product_image_path
FROM
products AS p
INNER JOIN
product_category AS pc
ON
p.product_id = pc.product_id
LEFT JOIN
vendor_products AS vp
ON
vp.product_id = pc.product_id
WHERE
pc.category_id = 2
AND
vp.vendor_id = 36
AND
pc.subcategory_id IN (1,2)
AND
pc.subcategory_value_id IN (1,4)
You want group by and having. It is a little unclear what you mean by "all conditions", but it would look something like this:
SELECT p.*
FROM products p JOIN
product_category pc
ON p.product_id = pc.product_id JOIN
vendor_products AS vp
ON vp.product_id = pc.product_id
WHERE pc.category_id = 2 AND
vp.vendor_id = 36 AND
(pc.subcategory_id, pc.subcategory_value_id) IN ( (1, 1), (2, 4) )
GROUP BY p.product_id -- this is okay because it is presumably the primary key
HAVING COUNT(DISTINCT pc.subcategory_id) = 2;
Notes:
The WHERE clause turns the LEFT JOIN into an INNER JOIN, so use the right JOIN.
I assume you want pairs of values from the subcategory table.
The HAVING clause insists on both subcatgories matching.
I have one product table like this:
productid categoryid
and another category table like this:
categoryid parentid
would like to find rows missing from product table
select distinct c.parentid, pc.productid, from products_categories pc
join categories c on pc.categoryid = c.categoryid
where concat(pc.productid,'-',c.parentid) not in (
select distinct concat(productid,'-',categoryid) from products_categories
)
however this is extremely slow. is there a way to do this with joins instead of the not in concat line? the concat is used to account for all possible combos.
Everytime you are adding a prefix productID & - to either parentID or categoryID.
You can try this:
SELECT DISTINCT c.parentid, pc.productid
FROM products_categories pc
JOIN categories c on pc.categoryid = c.categoryid
WHERE c.parentid NOT IN (
SELECT DISTINCT categoryid FROM products_categories
)
Edit 1: doesnt account for all combos
SELECT DISTINCT c1.parentid, pc.productid
FROM products_categories pc
INNER JOIN categories c1 ON pc.categoryid = c1.categoryid
LEFT JOIN categories c2 ON c1.parentid = c2.categoryid
WHERE c2.categoryid IS NULL
To find what is in tbl_x but not in tbl_y, do this
SELECT ...
FROM tbl_x
LEFT JOIN tbl_y USING(...)
WHERE tbl_y.id IS NULL;
The construct IN ( SELECT ... ) is very poorly optimized. LEFT JOIN is well optimized (assuming suitable index).
I have a stored procedure where i want to grab some data through a connection table. The database is old and have no constraint.
This is my procedure:
select distinct(p.id), pd.language, p.Company, pd.shortDescription from dbo.Category c
join dbo.ProductCategory pc on c.id = pc.CategoryId
join dbo.Product p on pc.id = p.id
join dbo.ProductDescription pd on p.id = pd.id
where
c.Company = 'Normstahl' and
c.languageid = 'en' and
p.Company = 'Normstahl' and
pc.Company = 'Normstahl' and
c.id != 'Deckenlauf' and
pd.language = 'en' and
pd.Company = 'Normstahl'
and as you can see i want to select products that is not connected to the category 'Deckenlauf'.
the problem is that if a product is connected to multiple categories i will recive the product that is connected to that category anyway since it just skips the product that is connected to the category but finds the same product that is connected to another category.
id CategoryId Company
1 Deckenlauf Normstahl
1 RGD_EUR9_DL Normstahl
this is from the connectiontable between category and product. So in my stored procedure i don't want to recieve any products with the id = 1 but now i will because if takes the second row since it is not connected to the category 'Deckenlauf'. How can i solve this problem in my stored procedure?
I solved it like this:
select distinct(p.id), pd.language, p.Company, pd.shortDescription from dbo.Category c
join dbo.ProductCategory pc on c.id = pc.CategoryId
join dbo.Product p on pc.id = p.id
join dbo.ProductDescription pd on p.id = pd.id
where
c.Company = #companyName and
c.languageid = #languageId and
p.Company = #companyName and
pc.Company = #companyName and
c.id != #categoryId and
pd.language = #languageId and
pd.Company = #companyName and
p.id not in (select id from ProductCategory where CategoryId = #categoryId)
by adding the last select
I would try using a LEFT JOIN with a condition/filter and WHERE IS NULL to check whether the product has any links to the chosen category.
While your subselect solution most definately would work and maybe be more readable the it should give you better performance.
Assuming I've understood how you use your input parameters to the stored procedure it would be something like this:
LEFT JOIN dbo.ProductCategory pc on pc.id = p.id AND pc.CategoryId = #categoryId -- Only join for the chosen category
WHERE pc.CategoryId IS NULL and -- Only include rows which did not "hit" the left join
I've updated your solution and also moved what seemed to me to be join conditions, i.e. the pd.Company and pc.Company to the ON part.
In addition I've removed the join to Category as you don't seem to use it in the select.
Which gives the following query:
select distinct(p.id), pd.language, p.Company, pd.shortDescription
from dbo.Product p
left join dbo.ProductDescription pd on p.id = pd.id AND pd.Company = p.Company AND pd.languageid = #languageId
left join dbo.ProductCategory pc on pc.id = p.id AND pc.Company = p.Company AND pc.CategoryId = #categoryId
where pc.CategoryId IS NULL -- No matching category exists
and p.Company = #companyName
Note that the left join to ProductDescription is there to include rows in the result even for products that do not have a description for the supplied #languageid, as this is how the query in your solution would work.
This could/should be changed to an inner join if products should only be included in the result if they do have a description.
I have three tables
profiles (id, name, deleted)
categories (id, name, deleted)
profiles_categories (id, profile_id, category_id, , deleted)
How i can select all profiles with name in categories?
I trying something like this, but its not works...
SELECT *
FROM profiles p
JOIN categories c, profiles_categories pc
WHERE p.id = pc.profile_id
AND WHERE pc.id = c.category_id
Thanks
EDIT
SELECT *
FROM profiles p
INNER JOIN profiles_categories pc
ON p.id = pc.profile_id
INNER JOIN categories c
ON pc.id = c.id
its return only for one profile (now only two active profiles, but only first have categories)
You have several issues with your current query.
First, you are mixing join types. You should use ANSI JOIN syntax between all of the tables. Don't mix ANSI JOIN syntax with some tables and then commas between other tables.
Second, you have two WHERE clauses and you can only have one WHERE clause.
Finally, you should include the column names that you want to return instead of SELECT *
The query should be similar to this:
SELECT p.name, c.name
FROM profiles p
INNER JOIN profiles_categories pc
ON p.id = pc.profile_id
INNER JOIN categories c
ON pc.id = c.category_id
An INNER JOIN between the tables will return all rows that exist in all of the tables.
Note, based on your table structure you might be able to use the following which returns the profiles that have a corresponding row in the the profiles_categories table:
select p.name
from profiles p
where p.id in (select profile_id
from profiles_categories);
Edit you want to return all profiles regardless of whether or not then have a category, then you need to use a LEFT JOIN:
SELECT p.name, c.name
FROM profiles p
LEFT JOIN profiles_categories pc
ON p.id = pc.profile_id
LEFT JOIN categories c
ON pc.id = c.category_id
SELECT *
FROM profiles p
JOIN profiles_categories pc on p.id = pc.profile_id
JOIN categories c on pc.id = c.category_id
or
SELECT *
FROM profiles p, categories c, profiles_categories pc
WHERE p.id = pc.profile_id
AND pc.id = c.category_id
try this:
SELECT *
FROM profiles p
JOIN profiles_categories pr on p.id = pr.profile_id
JOIN categories c on pr.id = c.category_id
WHERE c.name='thename'
I have three tables, product, category and product_to_category. Product has the primary key product_id, category category_id and product_to_category p2c_id. Product_to_ category links products to categories in a many-to-many relationship using their respective ID's.
Basically I want to write a query that would select all products from categories that do not exist in the category table. This is due to products being migrated across from another database.
I had something like this but was a little lost.
SELECT *
FROM product AS p
LEFT JOIN product_to_category AS p2c ON p.product_id = p2c.product_id
LEFT JOIN category AS c ON c.category_id
Basically that is as far as I have got. I need to join the category table to the product_to_category table where the product_to_category category_id is not in the category table. I may be completely on the wrong path but am stuck!
Thanks in advance.
Assumption: A product can be part of categories that exist, categories that do not exist, or no categories at all. You have not asked for products that belong to no categories at all, so the first LEFT JOIN from product to procduct_to_category should be an INNER JOIN.
Caveat: I am rusty at mysql so I am using SQL SERVER syntax. I forget if mysql has ON clauses or uses where clauses for JOINs. If ON clause is not supported, change them into WHERE clauses.
There are two common approaches: OUTER JOIN or a NOT IN clause (or a NOT EXISTS clause, which often behaves the same performance-wise as the NOT IN clause.)
OUTER JOIN
select p.*, p2c.category_id
from product p
INNER JOIN product_to_category p2c ON (p.product_id = p2c.product_id)
LEFT JOIN category c ON p2c.category_id = c.category_id
WHERE c.category_id IS NULL
The test for null will find the unmatched records.
NOT IN clause
SELECT p.*, p2c.category_id
FROM product p
INNER JOIN product_to_category p2c ON (p.product_id = p2c.product_id)
WHERE p2c.category_id NOT IN (SELECT c.category_id FROM category c)
If you're looking for products from nonexistent categories, I'd suggest
Select p.*,p2c.category_id
from product p
join product_to_category p2c
on p.product_id=p2c.product_id
left outer join category c
on p2c.category_id=c.category_id
where c.category_id is null
SELECT p.*
FROM product AS p
LEFT JOIN product_to_category AS p2c ON p.product_id = p2c.product_id
WHERE NOT EXISTS (
SELECT 1
FROM category c
WHERE c.category_id = p2c.category_id
)
SELECT *
FROM product AS p
JOIN product_to_category AS p2c ON p.product_id = p2c.product_id
JOIN category AS c ON c.category_id != as.category.
Try this?