SQL GROUP_CONCAT with LEFT JOIN to multiple relative rows - mysql

I have been stuck on this for hours now, any help would be greatly appreciated
I have two tables 'products' and 'product_subcategorys'
'products' holds only unique ids where as 'product_subcategorys' holds multiple ids relative to the 'products' table
'products'
id brand
1 a
2 b
3 a
'product_subcategorys'
id subcat
1 u
1 i
2 u
3 u
this is the query I have, Group by 'p.id' doesn't appear to work
SELECT GROUP_CONCAT(p.brand)
FROM products p
LEFT JOIN product_subcategorys s ON p.id = s.id
WHERE (
s.subcategory = "u"
OR s.subcategory = "i"
) AS GROUPbrand
So my problem is, i want it to return the list of brands only from the 'product' table I cant use distinct because i need to count the multiples
I want the query to return brand 'a' twice, but this query is returning it 3 times since there are two matching ids in the 'product_subcategorys'

Does this do what you want?
SELECT GROUP_CONCAT(p.brand ORDER BY p.id)
FROM products p
WHERE EXISTS (SELECT 1
FROM product_subcategorys s
WHERE p.id = s.id AND
s.subcategory IN ('u', 'i')
);

Related

How do I apply filters from multiple rows to a joined table in MySQL? [duplicate]

This question already has answers here:
SELECTING with multiple WHERE conditions on same column
(12 answers)
Closed 2 years ago.
I am working on a project where I'd like to display products that are subject to certain filters. Let's say I have the following 2 tables:
Products
id name
--------------
1 'Product 1'
2 'Product 2'
Filters
product_id filter_id
----------------------
1 a
1 b
2 a
I'm trying to write a query that only returns products if the filters are set. So if filter 'a' is active the results should be product 1 and 2, and if 'a' AND 'b' are active it should ONLY return product 1.
I've tried:
SELECT p.id
FROM products p
LEFT JOIN filters f ON f.product_id = p.id
WHERE filter.id = 'a'
GROUP BY p.id
This returns the id's for product 1 and 2 as expected. However, when I try:
SELECT p.id
FROM products p
LEFT JOIN filters f ON f.product_id = p.id
WHERE filter.id = 'a' AND filter.id = 'b'
GROUP BY p.id
I'd expect it to return the id for product 1, but it returns no results. How can I rewrite my query so that I get the product id's for the active filters? Can this be done with MySQL alone or do I have to loop through the results with php?
Your query just needs a slight change: Use OR instead of AND...change it to this:
SELECT p.id
FROM products p
LEFT JOIN filters f ON f.product_id = p.id
WHERE filter_id in ('a','b')
GROUP BY p.id
HAVING COUNT(*) = no_of_filters

Many-To-Many select only rows with exactly same tags

I have 3 tables: tags, products and relation table between them.
Relation table looks for example like this:
tagId | ProductId
1 | 1
2 | 1
2 | 9
The user can pick two options "All of these" or "One of these".
So if user picks All of these, it's means that the product must have exactly all of tags which the user chose.
So if user pick tags with id 1 and 2, it should select only product with id 1, because this product has exactly the same tags the user chose. (Another way is if the user picks the tag with id 2, it should select only product with id 9.)
So, the product has to have all tags which the user chose (no more, no less).
SQL that I already have for Any/One of these:
SELECT DISTINCT s.SKU
FROM SKUToEAN as s
LEFT JOIN ProductDetails as p ON s.ProductDetailID=p.id
JOIN ProductTagRelation as ptr ON (ptr.productId=p.id and ptr.tagId IN(Ids of selected tags))
Example behavior:
TagId = 1 it should select => None
TagId = 2 it should select => 9
TagId = 1,2 it should select = 1,9
So probably I need two queries. One for any/one of these ( I already have this one ) and the second for all of these.
With PHP I decide which query to use.
You can GROUP BY on the ProductID and use conditional aggregation based filtering inside the Having clause. MySQL automatically casts boolean values to 0/1 when using in numeric context. So, in order to have a specific tagID value available against a ProductID, its SUM(tagId = ..) should be 1.
All of these:
SELECT ptr.productId, s.SKU
FROM SKUToEAN AS s
LEFT JOIN ProductDetails AS p
ON p.id = s.ProductDetailID
JOIN ProductTagRelation AS ptr
ON ptr.productId = p.id
GROUP BY ptr.productId, s.SKU
HAVING SUM(ptr.tagID = 1) AND -- 1 should be there
SUM(ptr.tagID = 2) AND -- 2 should be there
NOT SUM(ptr.tagID NOT IN (1,2)) -- other than 1,2 should not be there
Is this you are looking for (for all condition)?
select product.id
from products
inner join <table> on products.id = <table>.productId
group by product.id
having group_concat(<table>.tagId order by <table>.tagId separator ',') = '1,2';

Pull data from 3 tables

I have 3 tables as follows :
Table 1: Product
id_product [Primary Key],added_time.
Table 2: Category
id_category [Primary Key],Category_name.
Table 3: product_category
id_category,id_product [Both Foreign Keys]
I want to pull Data as
Category_name,No Of Products in this Category,Last time when product was added to Category(Latest product added_time).
You could use this SQL:
SELECT Category.Category_name,
Count(DISTINCT Product.id_product) AS num_products,
Max(Product.added_time) last_added_time
FROM Category
LEFT JOIN product_category
ON product_category.id_category = Category.id_category
LEFT JOIN Product
ON Product.id_product = product_category.id_product
GROUP BY Category.Category_name;
Note that by using LEFT JOIN you will be certain to list all categories even those for which no products exist. If you don't want those, replace both LEFT keywords with INNER.
Note also that in standard SQL you need to GROUP BY any columns you mention in the SELECT list, unless they are aggregated, like with MAX or COUNT.
SELECT C.`Category_name`,
(SUM(IF(P.`id_product`IS NULL,0,1))) AS No_of_Products,
MAX(P.`added_time`) AS Latest_time
FROM
Category C
LEFT JOIN
product_category P_C ON C.`id_category` = P_C.`id_category`
LEFT JOIN
Product P ON P.`id_product` = P_C.`id_product`
GROUP BY C.`id_category`
Hope this helps.

MySQL Queries - Selecting from 2 tables and if exists in the other check field

I am trying to pull products from a table called products, I also have a table called product_ranges.
products
--------
id
name
model
product_ranges
--------------
id
product_id
other_id
SELECT p.id
FROM products As p
LEFT JOIN product_ranges As pr ON (pr.product_id = p.id AND pr.other_id = 16)
This will select all products and include the product_ranges table columns too if the product exists in it but if it does exist in this table and the other_id does not equal 16 I don't want the product to be in the returned results but if the product doesn't exist at all in the other table I want it in the results still.
I am sure I have done this years ago but can't think of the SQL for it - if anyone knows the right query I would be grateful, thanks.
Updated:
SELECT p.id
FROM products
LEFT JOIN product_ranges pr ON pr.product_id = p.id
WHERE (pr.product_id IS NULL OR pr.other_id = 16)

PHP MYSQL - Returning values that are not the same

I want to compare fields in 2 tables to see if the fields have the same values.
For e.g.
- I have 2 tables, 'products' and 'wishlist'.
- In both tables, they have the same fields 'prodId' and 'userId', plus other fields like 'title', etc.
- The 'wishlist' table contains some of the same rows that are in table 'products'(e.g. 10 in total in 'products' but only 6 of the same rows are in table 'wishlist')
- I want to display the fields/rows from table 'products', that are different from table 'wishlist', so from the e.g. it will only show 4 (so it does not show duplicates of the 6),so to do this I would like to use fields 'prodId' and 'userId', in the table 'products', and compare this to the same fields in the table 'wishlist'.
How would I do this?
Thanks.
A JOIN will return you all records that have matching values in both tables:
SELECT *
FROM
products p
JOIN wishlist w ON w.userId = p.userId AND w.prodId = p.prodId
EDIT:
To return all records that are not matching:
SELECT *
FROM
products p
FULL OUTER JOIN wishlist w ON w.userId = p.userId AND w.prodId = p.prodId
WHERE
p.Id IS NULL
OR w.Id IS NULL
EDIT:
To show records in products that don't have a match in wishlist, use a LEFT JOIN:
SELECT *
FROM
products p
LEFT JOIN wishlist w ON w.userId = p.userId AND w.prodId = p.prodId
WHERE
w.Id IS NULL