2016-01-05 167 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」無效 –