I’m really struggling with this now, been on it for ages and asked two questions on here already!
So, here’s a hopefully more defined question.
I have a product database with several thousand products.
Products can be grouped by item so as not to display in my search results multiple items that are essentially the same but with different finishes.
So, a simple select query would look like:
SELECT * FROM products GROUP BY item
This would give me all the products showing just one per item (the idea being that the viewing customer clicks something else to show all the finish options)
I could get my finish options using something like
SELECT *, GROUP_CONCAT(finishes) FROM products GROUP BY item
BUt… and here’s where I have problems
In my search results pages, the “random” order of the grouping is no good to me. I need to be able to have the displayed item from the group clause depending on the following condtions
- If there is no stock of any finish, then display the cheapest option
- If there is stock, then display the cheapest item which is in stock
Getting just an ID is no good, I need the full record, so somehow what I need is a condition statement to determine the order in which the grouped records are presented to ensure that the item that I get from the recordset meet the criteria above.
I simply cannot work out how to do this, I’ve tried millions of different INNER JOIN and `CASE scenarios, but just can’t get it to work.
Here’s where I have got to this morning:
SELECT * FROM products prod INNER JOIN
(SELECT id, item, MIN(price) AS minPrice, totalStock, MAX(totalStock) AS maxStock,
sum(totalStock) as sumTotalStock FROM products WHERE " & whereClause & "
GROUP BY item ORDER BY price) sortedProd ON
CASE WHEN sortedProd.sumTotalStock > 0 THEN " ' if there is some of this item in stock
CASE WHEN sortedProd.minPrice = prod.price AND sortedProd.item = prod.item AND sortedProd.totalStock > 0 THEN ' check if the item in stock is the cheapest
sortedProd.minPrice = prod.price AND sortedProd.item = prod.item " ' if the cheapest one is ins tock, display it
ELSE sortedProd.totalStock > 0 AND sortedProd.item = prod.item END" 'if not display whichever is in stock
ELSE sortedProd.minPrice = prod.price AND sortedProd.item = prod.item END ' otherwise display the cheapest
GROUP BY prod.item ORDER BY prod.price DESC
This is giving me results, but form reason some items are being excluded from the results, and the sorting order is still not correct.
To answer @DRapp below, here’s some basic sample data
item | price | finish | totalStock
item 1 | £1 | red | 2
item 1 | £1 | blue | 1
item 1 | £1.50 | blue & red | 1
item 2 | £2 | red | 0
item 2 | £3 | blue | 1
item 3 | £3.50 | blue & red | 1
item 3 | £1 | red | 0
item 3 | £2 | blue | 1
item 4 | £4.50 | blue & red | 1
item 5 | £1.50 | blue | 0
item 5 | £2.50 | green | 0
item 5 | £0.50 | orange | 0
The result I’d like to see is:
- item 1, red (sumTotalStock = 4) – ‘red and blue are both cheapest & in stock. Either result shown is fine, but to be 100% perfect, show red as the stock is greatest
- item 2, blue (sumTotalStock = 1) -‘ blue is the only finish in stock
- item 3, blue (sumTotalStock = 2) – ‘display blue as it’s cheapest in stock
- item 4, blue & red (sumTotalStock = 1) -‘there are no finish options, so just show this one regardless of stock/price
- item 5, orange (sumTotalStock = 0) – ‘none in stock, but show orange as it’s cheapest.
Obviously there is more data to actually display than just finish and price, product description etc also, which may vary depending on finish, hence I do need to get the full record, but this data example should explain the principle.
This should do what you want using a “simple” left join and no nested selects; your sort criteria make the query look a bit bulky though 🙂
Demo here.