2008-10-09 84 views
3

我剛剛學會(昨天)使用「存在」而不是「in」。SQL - 表別名範圍

BAD 
select * from table where nameid in ( 
      select nameid from othertable where otherdesc = 'SomeDesc')  
GOOD 
select * from table t where exists ( 
      select nameid from othertable o where t.nameid = o.nameid and otherdesc = 'SomeDesc')  

而且我對此有些疑問:

1)我的理解是解釋:「之所以這樣比較好是因爲只有匹配的值將被替代返回構建一個龐大的可能結果列表「。這是否意味着雖然第一個子查詢可能返回900個結果,但第二個子查詢只返回1個(是或否)?

2)在過去,我有RDBMS抱怨:「只有前1000行可能被檢索」,這第二種方法可以解決這個問題嗎?

3)第二個子查詢中別名的範圍是什麼?......別名只存在於括號中嗎?

例如

select * from table t where exists ( 
      select nameid from othertable o where t.nameid = o.nameid and otherdesc = 'SomeDesc')  
AND 
      select nameid from othertable o where t.nameid = o.nameid and otherdesc = 'SomeOtherDesc')  

也就是說,如果使用相同的別名(鄰爲表othertable)在第二個「存在」,它將出現任何問題與所述第一存在?還是他們完全獨立?

這是Oracle僅與其相關或對多數RDBMS有效嗎?

非常感謝

+0

它的「存在」,而不是「存在」。 – Constantin 2008-10-09 19:41:29

回答

3

它是特定於每個DBMS並取決於查詢優化器。一些優化器檢測IN子句並翻譯它。

在我測試了所有的DBMS,別名只是裏面的()

有效BTW,你可以重寫查詢爲:

select t.* 
from table t 
join othertable o on t.nameid = o.nameid 
    and o.otherdesc in ('SomeDesc','SomeOtherDesc'); 

而且,爲了回答你的問題:

1

就我個人而言,我會使用連接,而不是子查詢。

SELECT t.* 
FROM yourTable t 
    INNER JOIN otherTable ot 
     ON (t.nameid = ot.nameid AND ot.otherdesc = 'SomeDesc') 
2
  1. Oracle特有的:當你寫使用IN子句的查詢,你告訴你想要的內部查詢來驅動外部查詢的基於規則的優化。當您在where子句中編寫EXISTS時,您告訴優化器您希望首先運行外部查詢,並使用每個值從內部查詢中獲取一個值。請參閱"Difference between IN and EXISTS in subqueries"
  2. 也許。
  3. 在子查詢中聲明的別名位於子查詢中。順便說一句,我不認爲你的例子2 ANDed子查詢是有效的SQL。你是說UNION而不是AND?
3

您正在步入複雜的領域,被稱爲「相關子查詢」。由於我們沒有關於表格和關鍵結構的詳細信息,因此一些答案只能是「可能」。

在您的初始IN查詢中,無論OtherTable是否包含列名稱ID(實際上,OtherDesc是否作爲Table或OtherTable中的列存在 - 在您的任何示例中都不清楚,大概是OtherTable的一列)。這種行爲是將相關的子查詢變爲相關的子查詢的原因。它也是人們初次遇到它時常常感到焦慮的原因 - 總是偶然發生。由於SQL標準要求在子查詢作爲參照外部查詢一欄詮釋一個名字,如果有與子查詢中提到的表中的相關名稱的列,但有一列與行爲外部(主要)查詢中提到的表中的相關名稱,沒有任何產品聲稱符合SQL標準(的這一點)將做任何不同的事情。

您對Q1的回答是「依賴」,但給出了合理的假設(NameID作爲兩個表中的列存在; OtherDesc僅存在於OtherTable中),結果應該與返回的數據集相同,但在性能方面可能並不相同。

回答你的第二季度是過去,你使用劣質如果不是有缺陷的數據庫管理系統。如果它支持EXISTS,那麼DBMS可能仍然抱怨結果的基數。

適用於第一EXISTS查詢回答你的Q3是「T可作爲整個語句的別名,但o是僅作爲括號內的別名」。應用於你的第二個示例框 - 用AND連接兩個子選擇(其中的第二個子選擇在我查看時忽略了左括號),則「t在整個語句中作爲別名可用並且指代相同表,但有兩個不同的別名,都標爲'o',每個子查詢一個「。請注意,如果OtherDesc對於OtherTable中的給定NameID值唯一,則查詢可能不會返回數據;否則,它需要具有相同NameID的OtherTable中的兩行和具有該NameID值的Table中每行的兩個OtherDesc值。

1

這是很難一概而論存在總是比更好。從邏輯上講,如果是這樣的話,那麼SQL社區將用EXISTS取代IN ... 另外,請注意IN和EXISTS不一樣,當你使用兩個時,結果可能會不同...

With IN,通常內表的一次不刪除空值(所以,如果你在你的內心表值爲空,IN不會刪除默認NULLS)......雖然EXISTS其全表掃描消除NULL和相關子查詢的情況下,從外部查詢的每一行運行內部查詢。

假設沒有出現任何空值和它的一個簡單的查詢(無相關性),如果有則您發現該行不是最後一個行可能有更好的表現。如果恰好是最後一排,存在,則可能需要掃描,直到最後如IN ..所以類似的性能...

但在和EXISTS是不能互換的...