2016-01-05 132 views
2

的最大值我有这已经工作的SQL语句,但我认为必须有比我更好的解决方案。SQL查询:选择再选择

我试图得到文章与已从未出售最高价

有了这个选择我收到尚未售出的所有文章(数+价格):

select anr, price 
from article a 
where not exists(
    select 1 from OrderItems o 
    where o.artnr = a.anr 
) 

的文章编号+价格结果如下

| Anr | Price | 
| 1 | 300.0 | 
| 4 | 340.0 | 
| 5 | 340.0 | 
| 3 | 200.0 | 

我临时解决方案获得价格最高的商品是:

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 
) 
) 

正确的解决方案是:

| Anr | Price | 
| 4 | 340.0 | 
| 5 | 340.0 | 

有没有办法避免两次使用相同的子查询?

为了测试这里是缩短了与我的插入值创建表的脚本:

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); 

我也阅读主题Select max value in subquery SQL 但我觉得在我的情况下,必须有做选择较短的方式。

+0

的SQL Server/MySQL的/甲骨文/ PostgreSQL的/火鸟/ SQLite的? – lad2025

+0

它应该适用于每个数据库,这就是为什么我不需要特定的数据库。我想通过使用标准的SQL来解决这个问题。 但我正在测试Oracle 12c :) – Johnny90

+0

如果您添加脚本以创建表和记录..我可以帮你 – rdn87

回答

2

这里是避免了您有相关子查询的一个解决方案,而不是用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) 

这个解决方案应该是ANSI-92兼容,这意味着它应该发挥的友好与MySQL,甲骨文,SQL Server以及您可能遇到的任何其他类型的快餐。

+0

非常感谢Tim :) – Johnny90

+0

它并不真正“避免”共同相关的子查询。外连接几乎是一回事,任何现代优化器都可能使用相同的执行计划。 –

+0

@a_horse_with_no_name优化器是否也能够平滑处理'WHERE'子句中的子查询,并认识到它与外部查询无关? –

-1

您可以同时使用原来的查询与窗函数来获得你想要的东西:

select anr, price 
from (
    select anr, price, max(price) over() as max_price 
    from article a 
    where not exists (select 1 
         from OrderItems o 
         where o.artnr = a.anr) 
) t 
where price = max_price; 

可能超过需要的article表更快只有一个单一的扫描。

或者您可以使用左连接解决方​​案,以发现那些从未被订购的文章,但我会感到惊讶,如果甲骨文将使用一个不同的执行计划:

select anr, price 
from (
    select anr, price, max(price) over() as max_price 
    from article a 
     left join OrderItems o ON o.artnr = a.anr 
    where o.artnr is null 
) t 
where price = max_price; 

SQLFiddle例如:http://sqlfiddle.com/#!15/1eb69/1

0
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 
      ) 

试试这个....

+0

在Oracle中,“TOP 1”无效 –