I have 5 tables: productCategory, products, productOptions, options, optionsGroup. What I'm trying to do is somehow concat and group them into one query to return one row with all information about one product. For example, a certain type of food will have different sizes and different flavors; bottles have different sizes and smells. Here are the tables:
productCategory
categoryId categoryName
1 food
2 freshener
product
productId productCategoryRef productName
1 1 ....
2 1
3 2
4 2
FK references categoryId
productOptions
categoryRef optionsRef
1 1
1 3
2 2
2 4
FK categoryRef references productCategory (categoryId)
FK optionsRef references options (optionsId)
options
optionsId optionsName
1 kg
2 ml
3 Flavor
4 Fragrance
optionsGroup
groupId groupOptionRef groupName
1 1 3
2 1 7
3 1 14
4 2 50
5 2 250
6 3 Chicken
7 3 Beef
8 4 Alpine
9 4 Berries
FK groupOptionRef references options (optionId)
So a food bag can be 3kg, 7kg or 14kg and can have two different flavors. How can I get all this information in one row in a readable format? Here's what I tried:
SELECT
pc.*, p.*,
GROUP_CONCAT(DISTINCT o.optionsName) AS optionName,
GROUP_CONCAT(og.groupName) AS options
FROM productCategories pc
JOIN products p ON p.productCategoryId=pc.categoryId
JOIN productOptions po ON po.categoryRef=pc.categoryId
JOIN options o ON o.optionsId=po.optionsRef
JOIN optionsGroup og ON og.groupOptionRef=o.optionsId
WHERE p.productName=:itemName
GROUP BY p.productId
This gives me one row with
....
optionName: 'kg,Flavor',
options: '3,7,14,Chicken,Beef'
....
which is a mess. Is it possible to somehow concat each option together and then post-process it easier without having to guess which part goes to kg/Flavor?
I know it would be easy here but later there will be a review section which will reference this productId which I would like to join as well to this query. Any advice is appreciated, I'm open to a better DB structure if one is needed.
If you don't mind option names being repeated, you can group_concat a concat like this:
GROUP_CONCAT(CONCAT(o.optionsName, ': ', og.groupName) ORDER BY o.optionsName, og.groupName) AS options
If you want any more structured than that, you'd have to subquery (grouping by option name, and group_concating it's group names; then grouping without option name in the outer query); but at that point it is definitely worth considering if you should just be handling formatting and grouping the results client side.