Reputation: 503
I've got a sql statement which already works, but i think there must be a better solution than mine.
I'm trying to get the articles with the highest price which have never been sold.
With this select I'm getting all the Articles (number + price) that haven't been sold yet:
select anr, price
from article a
where not exists(
select 1 from OrderItems o
where o.artnr = a.anr
)
The article number + price result looks like
| Anr | Price |
| 1 | 300.0 |
| 4 | 340.0 |
| 5 | 340.0 |
| 3 | 200.0 |
My temporary solution to get the articles with the highest price is:
select anr, price
from article
where anr in(
select anr
from article a
where not exists(
select 1 from OrderItems o
where o.artnr = a.anr
)
)
and price = (
select max(price)
from article a
where not exists(
select 1 from OrderItems o
where o.artnr = a.anr
)
)
The correct solution is:
| Anr | Price |
| 4 | 340.0 |
| 5 | 340.0 |
Is there a way to avoid having the same subselect twice?
For testing here is the shortened Create Table script with my insert values:
CREATE TABLE Article
(
Anr Int Primary Key,
Price Numeric(9,2) Not Null
);
CREATE TABLE Orders
(
OrderNr Int Primary Key
)
CREATE TABLE OrderItems
(
OrderNr Int References Orders On Delete Cascade,
ItemNr Int,
Artnr Int References Article Not Null,
Amount Int Not Null Check(Amount >= 0),
Primary Key(OrderNr, ItemNr)
)
-- articles without an order
Insert into Article (Anr, Price) values(1,300.0);
Insert into Article (Anr, Price) values(4,340.0);
Insert into Article (Anr, Price) values(5,340.0);
Insert into Article (Anr, Price) values(3,200.0);
-- articles for order with orderNr '1'
Insert into Article (Anr, Price) values(2,340.0);
Insert into Article (Anr, Price) values(6,620.0);
-- insert test order that contains the two articles
Insert into Orders (OrderNr) values (1);
Insert into OrderItems(OrderNr, ItemNr, Artnr, Amount) values(1,1,2,4);
Insert into OrderItems(OrderNr, ItemNr, Artnr, Amount) values(1,2,6,2);
I also read the topic Select max value in subquery SQL but I think in my case there must be a shorter way of doing the select.
Upvotes: 2
Views: 4227
Reputation: 283
SELECT a.*
FROM article a LEFT JOIN OrderItems o ON a.anr = o.artnr
WHERE o.artnr IS NULL
AND a.price = (SELECT TOP 1 a.price
FROM article a LEFT JOIN OrderItems o ON a.anr = o.artnr
WHERE o.artnr IS NULL
Order By a.price Desc
)
Try this ....
Upvotes: 0
Reputation: 520918
Here is a solution which avoids one of the correlated subqueries you had, instead replacing it with a LEFT JOIN
:
SELECT a.*
FROM article a LEFT JOIN OrderItems o ON a.anr = o.artnr
WHERE o.artnr IS NULL AND
a.price = (SELECT MAX(a.price)
FROM article a LEFT JOIN OrderItems o ON a.anr = o.artnr
WHERE o.artnr IS NULL)
This solution should be ANSI-92 compliant, meaning it should play friendly with MySQL, Oracle, SQL Server, and any other type of fast food you might encounter.
Upvotes: 3