2012-01-16 31 views
0

我在表A(列IDDESC)和B(列FK_ID,CODE)之間有一對多的關係。 ID - >FK_ID在連接表中選擇值和非值的有效SQL

我很想知道如何找到最有效的SQL來選擇A中的所有行,其中B中有一個名爲'C1'的代碼,但在名爲'N1'的B中有NOT代碼。

任何幫助表示讚賞。

+1

RDBMS是什麼? SQL Server? MySQL的?甲骨文? – JNK 2012-01-16 18:22:57

回答

3

使用EXISTSNOT EXISTS會給予最佳性能

SELECT tableA.* 
FROM tableA 
WHERE 
    EXISTS(
    SELECT NULL 
    FROM TableB 
    WHERE tableA.ID = TableB.FK_ID AND TableB.Code = 'C1') 
    AND NOT EXISTS(
    SELECT NULL 
    FROM TableB 
    WHERE tableA.ID = TableB.FK_ID AND TableB.Code = 'N1') 
+0

+1 - 我認爲這是最快的方法(假設爲SQL Server) – JNK 2012-01-16 18:31:16

+0

+1,儘管它可能無法提供最佳性能 - 在某些數據庫(包括MySQL中,我認爲)左外連接與外連接處的NULL表可以提供更好的性能。 – 2012-01-16 18:33:49

+0

@MarkBannister for MySQL如果兩邊的列不能爲空,那麼左連接與空檢查會更快,否則「存在」更好。對於SQL服務器「存在」總是更好(如果我沒有記錯的話)。 – Magnus 2012-01-16 18:44:17

0

我的理解(請糾正我,如果我錯了)就是你有兩個表所示:

create table A(ID int not null primary key, "DESC" varchar(30)); 
create table B(FK_ID int not null references A (ID), CODE varchar(30)); 

那麼像這樣的工作:

select 
    ta.* 
from 
    A as ta 
inner join 
    B as tb 
    on tb.FK_ID = ta.ID 
where 
    tb.CODE = 'C1' 
    and not exists (select null from B as tb2 where tb2.FK_ID = ta.ID and tb2.CODE = 'N1') 
1

選擇A中的所有行,其中B中有一個名爲'C1'的代碼,但B中沒有名爲'N1'的代碼。

我懷疑你的規範沒有準確地傳達你實際需要的東西!

字面解釋將是

if there exists a row in B where CODE = 'C1' 
    and there does not exist a row in B where CODE = 'B1' 
then return all rows from A 

(即,存在於A和B分別的值之間沒有相關性) 例如

SELECT * 
    FROM A 
WHERE EXISTS (
       SELECT * 
       FROM B 
       WHERE CODE = 'B1' 
      ) 
     AND NOT EXISTS (
         SELECT * 
         FROM B 
         WHERE CODE = 'C1' 
        ); 

然而,經驗(單獨)告訴我們,你可能想使用A.ID = B.FK_ID關聯的表。請參閱Magnus對一種方法的回答。

注意這裏提到的存在和非存在的操作符分別被稱爲semi joinsemi difference,它們可以用不同的方式寫入SQL。從性能的角度來看,效率最高的將取決於許多變量,包括SQL引擎,數據,索引,統計數據等。您將需要使用典型數據進行測試。還要考慮到可讀性和易維護性也是重要的因素。

此候選查詢(或類似的東西)是可能是值得考慮的,如果你選擇的SQL產品支持減號來EXCEPT(在Oracle中實際調用MINUS):

SELECT * 
    FROM A 
WHERE ID IN (
       SELECT FK_ID 
       FROM B 
       WHERE CODE = 'B1' 
       EXCEPT 
       SELECT FK_ID 
       FROM B 
       WHERE CODE = 'C1' 
      );