简体   繁体   中英

One product in many categories - PHP MySQL

I have a table products (id, barcode, catid, name, description, ...) and I've been asked to make it possible that some products can be assigned to more than one categories. The most obvious solution would be to change catid from INT to VARCHAR with delimited values ie 1,2,5 where 1,2 & 5 are the various categories.

Which SQL statement will do the job for me now? I have find_in_set in mind but I think it does the opposite.

The most obvious solution would be to create a 'cross-table' where you can do a many-to-many assignment (as in one category can have many products and one product can have many categories). This table would look like this:

product_id | category_id

You can then use this query:

SELECT 
  *
FROM 
  (product JOIN product_has_category ON product.id = product_has_category.product_id) 
      JOIN category ON product_has_category.category_id = category.id

You can even use normal WHERE and `ORDER BY, etc.

edit: Fixed a major error in my query, my appologies!


If you are unable to change the database, you might want to try this:

SELECT 
  *
FROM 
  category, product
WHERE
  product.id = ?? AND FIND_IN_SET(category.id, product.catid) > 0 GROUP BY product.id

Warning: It is a long shot, I haven't tested this, but as FIND_IN_SET would search a comma-seperated list, it could work.

Don't delimit your category ideas in a single field. You're setting yourself up for much pain. Use a many to many relationship.

products:
id,
barcode
...

category:
cat_id,
cat_name

product_category:
product_id
cat_id

To get all products in a particular category:

SELECT * FROM products JOIN product_category ON product_id=id WHERE cat_id=?

To get all categories for a product

SELECT * FROM category JOIN product_category ON product_category.cat_id = category.cat_id WHERE product_id=?

Your best bet would be to have a separate table with 'categories' and entries for each product. Normalize it this way.

If you don't want to do that, use a bitmask. Its much easier than parsing a comma delimited list of entries.

drop the catid and use a table that associates the id to one catid per row (cross-table).

I'd suggest the better solution would be to have a second table that maps product ids to categories, with an entry for each category that matches a product. It makes querying categories a little more complex by having to use JOIN, but is a more relational-database way than having a field with delimited values within the same table, which sounds like a nightmare to write queries for.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM