2012-02-28 120 views
1

我一直在爲星期四的考試做一些SQL,並且懷疑我是否正確使用了EXISTS語句。這是使用EXISTS的正確方法嗎?

所以,在這裏我有2個表

Machines    Maintenance 
    ============   ============== 
PK ID_Machine   PK ID_Machine FK 
    Name    PK ID_Task  FK 
    Date_bought    Date 

這樣一個數據庫,他們要我寫查詢說「顯示所有這一切並沒有收到任何維護在2011年的最古老的機器數據」

我做了如下的方式:

SELECT M.ID_MACHINE, M.NAME, M.DATE_BOUGHT 
FROM MACHINES M 
WHERE NOT EXISTS (SELECT MA.* 
        FROM MAINTENANCE MA 
        WHERE MA.ID_MACHINE = M.ID_MACHINE 
        AND YEAR(MA.DATE) = 2011)     
AND EXISTS (SELECT MIN(M2.DATE_BOUGHT) 
       FROM MACHINE M2 
       WHERE M2.ID_MACHINE = M.ID_MACHINE) 

這是做這個查詢的正確道路?在EXISTS語句中使用SELECT MIN()是否有意義?

在此先感謝大家!

+0

嗯....當您嘗試運行該查詢會發生什麼? – 2012-02-28 01:55:20

+0

那麼,問題是我實際上沒有在任何DBMS中創建此DB。這只是教科書中的練習,我正在用一張紙來解決它。不幸的是,教科書沒有答案,所以這就是爲什麼我問:) – nachoargentina 2012-02-28 02:00:30

+0

一開始,你需要一個'AND' *而不是*第二個'WHERE'。另外,絕對不要在'EXISTS'中使用'SELECT MIN()' - 這是沒有意義的。 – Bohemian 2012-02-28 02:17:53

回答

2

當您使用exists時,它僅驗證過濾器(連接和位置)返回的一段數據。通常情況下,您會看到存在查詢,其中select 1來自....這是因爲實際返回值未被使用。

這是一個新穎的想法,我必須親自測試一下。但是,正如我上面所述,大部分回報數據都被忽略。它只關心連接和過濾器匹配的位置,並不關心MIN,即使它看起來本身就是一個過濾器。它更像是一個聚合,所以底層數據看起來依然存在。第一個存在是有效的,但下一個部分確實需要工作。我已經更新了下面的內容,我會做什麼。

SELECT M.ID_MACHINE, M.NAME, M.DATE_BOUGHT 
FROM MACHINES M 
WHERE NOT EXISTS (SELECT 1 
       FROM MAINTENANCE MA 
       WHERE MA.ID_MACHINE = M.ID_MACHINE 
       AND YEAR(MA.DATE) = 2011)     
    AND M.ID_MACHINE = (SELECT TOP 1 M2.ID_MACHINE 
      FROM MACHINE M2 
      WHERE M2.ID_MACHINE = M.ID_MACHINE 
      ORDER BY M2.DATE_BOUGHT) 
+0

正確,那麼在我的情況下,與EXISTS條件我試圖選擇最古老的機器......這就是爲什麼我在子查詢的SELECT語句中包含一個MIN()。我認爲通過這樣做,EXISTS語句將會消除所有其他機器,但其中有MIN(Date_bought)的機器。是這樣嗎?還是我以錯誤的方式解決這個問題? – nachoargentina 2012-02-28 02:18:47

+0

更新我的回覆,但簡短的回答是,你確實是在錯誤地解決這個問題。這是一個新穎的主意,雖然:) – 2012-02-28 02:23:27

+0

對不起,忽略我的最後一條評論,我沒有閱讀你的評論,直到最後,只是第一段。那麼,你認爲它可能以這種方式工作?我認爲是這樣,因爲正如你所說,MIN()在理論上將作爲一個過濾器。只要有機會,我會嘗試在實際的數據庫中進行測試。 – nachoargentina 2012-02-28 02:24:35

0

我認爲這將是一個更好的方法去解決它。

SELECT TOP 1 MIN(A.Date_bought), A.ID_Machine, A.Name 
FROM Machines A 
JOIN Maintenance B on A.ID_Machine = B.ID_Machine 
WHERE DATEPART(year, B.Date) != '2011' 
GROUP BY A.Date_bought, A.ID_Machine, A.Name 
+0

-1:OP詢問他/她的查詢是否有效,而不是重寫它。 – 2012-02-28 02:06:43

+1

我認爲這會失敗,因爲'MIN'是聚集的,你沒有'GROUP BY' – Yuval 2012-02-28 02:07:14

+0

謝謝你,錯過了GROUP BY :)另外,對於傑克,他還問是否是正確的方式來做到這一點,我不知道我不認爲這是事實,所以我提供了另一種解決方案。當我在這裏只有8位代表時,無需投票。天啊。大聲笑 – stringpoet 2012-02-28 02:08:40

1

引述SQL-92 standard

8.8

 Function 

    Specify a test for a non-empty set. 

    Format 

    <exists predicate> ::= EXISTS <table subquery> 


    Syntax Rules 

     None. 

    Access Rules 


     None. 

    General Rules 

    1) Let T be the result of the <table subquery>. 

    2) If the cardinality of T is greater than 0, then the result of 
     the <exists predicate> is true; otherwise, the result of the 
     <exists predicate> is false. 

    Leveling Rules 

    1) The following restrictions apply for Intermediate SQL: 

      None. 

    2) The following restrictions apply for Entry SQL in addition to 
     any Intermediate SQL restrictions: 

      None. 

所以,不,也有在子查詢(只知道它是有效的)的語法,並沒有硬性規定。 exists聲明僅僅關心它是否返回任何行。

+0

好吧,在這種情況下,EXISTS語句將返回M2表中的一個特定行的真。由於該表對我的查詢中的主表有一個外部引用,這是否意味着通過這樣做,它將排除我的主表中的所有行,但具有MIN(Date_bought)值的行除外?因爲這基本上是我瞄準 – nachoargentina 2012-02-28 02:09:46

+0

不是,它不會從任何表中刪除任何行。它既不是'delete'也不是'truncate'語句。 – 2012-02-28 02:49:28

1

思考的EXISTSNOT EXISTS你可以釘到您查詢的WHERE子句的布爾條件。它們用於檢查其他數據條件是否與您正在查看的數據相關。

SELECT M.ID_MACHINE, M.NAME, M.DATE_BOUGHT 
FROM MACHINES M 

-- DO NOT want a machine with a maintenance year of 2011 
WHERE NOT EXISTS (SELECT 1 
        FROM MAINTENANCE MA 
        WHERE MA.ID_MACHINE = M.ID_MACHINE 
        AND YEAR(MA.DATE) = 2011)  

-- DO want there to be a matching ID in the Machine table    
WHERE EXISTS (SELECT 1 
       FROM MACHINE M2 
       WHERE M2.ID_MACHINE = M.ID_MACHINE) 

賈斯汀提到的,子查詢的返回值都沒有用,所以SELECT 1EXISTS/NOT EXISTS的慣例。

+0

但是,正如我剛剛編輯我的文章,MIN類型的行爲本身就像一個過濾器......所以我不知道是否有MIN會工作或不......。從來沒有嘗試過,理論上它可以工作。我更新了我對此的迴應。我可能會加載一些虛擬數據來看:) – 2012-02-28 02:19:48

+0

測試它,它失敗。我正在重新更新我的答案:) – 2012-02-28 02:22:17

+0

@JustinPihony好的,tx用於爲我測試!很高興知道那是不正確的。我喜歡它的男人。 – nachoargentina 2012-02-28 02:27:08

1

您的第一次使用EXISTS似乎是正確的,但第二個似乎是關閉。您想檢查機器是否最舊,但是您要檢查機器是否存在相同的MACHINE_ID(使用MINEXISTS函數的結果沒有影響)。

我不是數據庫管理員,但考慮到子查詢在某些實現中可能代價很高,而在其他實現中,它們可能會在放入EXISTS函數時進行優化。所以當你真的需要代碼運行時,應該考慮stringpoet的代碼......雖然我說你需要GROUP BY所有其他字段。

另請注意,您不應使用關鍵字WHERE兩次,但請將您的條件加入AND/OR

這裏是我的修正,你和stringpoet代碼:

SELECT M.ID_MACHINE, M.NAME, MIN(M.DATE_BOUGHT) 
FROM MACHINES M 
WHERE NOT EXISTS (SELECT MA.* 
        FROM MAINTENANCE MA 
        WHERE MA.ID_MACHINE = M.ID_MACHINE 
        AND YEAR(MA.DATE) = 2011)     
GROUP BY M.ID_MACHINE, M.NAME 
+0

好的,太棒了,這讓事情變得更加清晰! tx Yuval,我將使用你的代碼,而不是用EXIST的代碼作爲我的答案 – nachoargentina 2012-02-28 02:37:23

相關問題