Given a database of decimal values, grouped into locations ...
CREATE TABLE ItemPrices
(`Company` varchar(11), `LocationID` char(5), `ProductLevel` varchar(11), `LowPrice` decimal(5,2))
;
INSERT INTO ItemPrices
(`Company`, `LocationID`, `LowPrice`)
VALUES
('Company 1', 10001, 100.00),
('Company 2', 10001, 200.00),
('Company 3', 10001, 300.00),
('Company 4', 10001, 400.00),
('Company 1', 10002, 10.00),
('Company 2', 10002, NULL),
('Company 3', 10002, 30.00),
('Company 4', 10002, 40.00)
;
It's easy to select the lowest value for a location:
SELECT LocationID,min(LowPrice) FROM ItemPrices GROUP BY LocationID;
LOCATIONID MIN(LOWPRICE)
10001 100
10002 10
But using a subquery to filter out the lowest value and return the next lowest value doesn't work as expected:
SELECT LocationID,min(LowPrice) FROM ItemPrices
WHERE LowPrice >
(SELECT min(LowPrice)
FROM ItemPrices)
GROUP BY LocationID;
LOCATIONID MIN(LOWPRICE)
10001 100
10002 30
The result should show LocationID 10001's second-lowest price as 200, not 100.
Seems the subquery is just returning the lowest LowPrice
(10) in all cases. The proper logic would be to find the lowest price for that particular LocationID
(100), then find a larger value for that LocationID
(200) and return that larger value.
How can I make the subquery aware that it should be evaluating only a subset of the prices?
Just putting a GROUP BY
in there (LowPrice > (SELECT min(LowPrice) FROM ItemPrices GROUP BY LocationID)
) tells me Subquery returns more than 1 row
-- right, of course, it returns one row for every LocationID
.
In typing in this question, I have hit on the idea that I need a correlated subquery. The first step is to alias the table ItemPrices
. I'm using i
for the outer query and s
for the subquery.
SELECT i.LocationID,min(LowPrice) FROM ItemPrices i
WHERE
LowPrice >
(SELECT min(LowPrice)
FROM ItemPrices s
WHERE i.LocationID = s.LocationID)
GROUP BY LocationID;
Let's run it!
LOCATIONID MIN(LOWPRICE)
10001 200
10002 30
Looking good! What you think?
SQLFiddle: http://sqlfiddle.com/#!2/341ce/5