2009-01-30 51 views
4

實例查詢:我應該使用頂部(1)在一個子查詢

select * 
from A join B on A.ID = B.SOMEVALUE 
where A.VALUE="something" and 
B.ID = 
     (select ID from B where SOMEVALUE = A.ID and 
       THISDATE = (select max(SOMEDATE) from B where ...)) 

所以,如果你可以閱讀SQL你應該看到我做一對夫婦的相關子查詢縮小的連接的結果。 (是的,這是可怕的過度簡化)。

在某些情況下,子查詢:

select ID from B where SOMEVALUE = A.ID and 
    THISDATE = (select max(SOMEDATE) from B where ...) 

可以返回多個值,這將導致

「子查詢返回多個值 這是不允許的錯誤,當 子查詢遵循=,!=,<,< =,>,> = 或子查詢用作 表達式時。

我完全期待。這顯然不是一個好東西,我在地方的代碼(希望)防止這些重複從進入數據庫擺在首位(即表B中應該只有該

SOMEVALUE = A.ID and max(SOMEDATE) 

匹配1排標準),但最終用戶如果沒有創造力去尋找我想不到打破軟件的方式,則什麼都不是。

所以現在我的問題:

它會更好,以第一子查詢更改爲

select top 1 * from B ... 

,以防止用戶看到一個錯誤,如果(但願永遠)出現這種情況時/或讓錯誤通過。我傾向於不添加頂部語句並讓錯誤通過,而讓用戶看到可能不正確的數據。我想知道是否有人在這種情況下對最佳實踐有任何想法......

回答

0

爲什麼不在你的子選擇結束時使用LIMIT 1

+0

這也正是同樣的事情,加入TOP 1.這只是一種不同的味道的SQL(MySQL和等) – 2009-01-30 16:21:19

+0

同意邁克爾,這是一個不同的風味所以限制1可能不會在這句法實際工作。 – Kezzer 2009-01-30 16:22:26

+0

不回答這個問題,但它確實澄清了問題對於那些不熟悉TOP 1語法的人所暗示的問題。 – 2009-01-30 16:33:34

11

通常,TOP 1是一個好主意。

考慮一個包含數百萬行並且沒有索引的大表,您正在匹配的列上,但是您只查找單個行。

SELECT TOP 1將意味着只要找到一個項目就停止表掃描。

沒有TOP 1,表掃描將繼續直到最後。

就像任何涉及掃描(或蠻力)的搜索一樣。使用TOP 1時,它平均比未使用TOP 1時快50%。

但是,根據您需要返回的情況,通常可以通過使用EXISTS來獲得真正的性能增益。

而是寫

SELECT * FROM table t 
WHERE t.id = (SELECT TOP 1 foreignid from table2) 

的您可以使用

SELECT * FROM table t 
WHERE EXISTS (SELECT 1 from table2 WHERE foreignid = t.id) 
0

如果你正在尋找返回一個單行你可以做兩件事情之一。首先是要改變你的平等檢查,而不是檢查遏制像這樣

select ID from B where SOMEVALUE = A.ID and 
THISDATE IN (select max(SOMEDATE) from B where ...) 

(注意IN)

其次,你可以做

select TOP 1 ID from B where SOMEVALUE = A.ID and 
THISDATE IN (select max(SOMEDATE) from B where ...) 

,如果你只是想找一個值只要。

或者如你所說,你可以改變子查詢SELECT TOP 1,這在我看來是可以的,因爲只要WHERE子句不依賴於外部查詢,它可能會執行嵌套查詢只有一次,依靠靜態存儲的值從那裏出來,像這樣

select ID from B where SOMEVALUE = A.ID and 
THISDATE = (select TOP 1 * from B where ...) 

因此,有幾個選項,但我不能完全肯定他們的工作效率。

4

你爲什麼要加入表A和B ...然後在子查詢中從B中選擇...並與A中的列進行比較?

這豈不是等同的:

select * 
from A join B on A.ID = B.SOMEVALUE 
where A.VALUE="something" and 
THISDATE = (select max(SOMEDATE) from B where ...)) 

另外,如果你期望從這個整個查詢得到一個行總計..​​....這是不是工作:

select top 1 * 
from A join B on A.ID = B.SOMEVALUE 
where A.VALUE="something" 
Order by B.SOMEDATE DESC 
1

我'd推薦TOP 1方法。這可能會有助於表現(不會傷害它)。

沒有它你會發現錯誤的概念是光榮的,但有點錯位。如果從現在開始幾個月發生錯誤,那麼它爲什麼會發生或發生什麼事情將不會很直觀。相反,我會專注於在其他地方強化數據完整性。

4

編碼實踐:在需要返回單個值的子查詢中放置top1。

優點:

  • 允許繼續執行。
  • 允許查詢忽略不重要的額外值。
  • 找到第一個值(性能)時停止查找新值。

缺點:

  • 從抱怨顯著多餘的值阻止查詢。
  • 如果未在查詢中指定訂單,則無法控制top1將選擇哪個元素。當查詢再次執行時,這可能會導致不同的結果。
相關問題