2015-12-21 56 views
0

這裏是設置 -這是一種可接受的加入方式(左外連接表)嗎?

  create table tasks (taskno int, customerno int); 
      insert into tasks values (1, 100); 
      commit; 
      insert into tasks values (2, 200); 
      commit; 
      insert into tasks values (3, 300); 
      commit; 
      select * from tasks; 

      create table items (taskno int, accountno int); 
      commit; 
      insert into items values (1, 1000); 
      commit; 
      insert into items values (2, 2000); 
      commit; 
      select * from items; 

      create table accounts (accountno int, customerno int); 
      commit; 
      insert into accounts values (1000, 100); 
      commit; 
      insert into accounts values (1100, 100); 
      commit; 
      insert into accounts values (2000, 200); 
      commit; 
      insert into accounts values (3000, 300); 
      commit; 
      select * from accounts;  

我想基於一個accountno從任務表中的taskno。任務表只有一個叫做customerno的東西。此customerno可以與多個accountno關聯(將customerno視爲父母,並將accountno視爲小孩)。所以,如果你看看我們的設置,如果我通過在accountno 1000或者1100都將在該查詢返回taskno 1 -

  select a.taskno 
      from tasks a, accounts c 
      where a.customerno = c.customerno 
      and c.accountno = 1000 -- but will return taskno 1 also for 1100 

我想要一些更精細的細節莫過於此。所以我發現了另一個表'Items',它有taskno和accountno。所以,如果我把它添加到查詢,它會返回正確的taskno 1 accountno 1000而不是1100

  select a.taskno 
      from tasks a, items b, accounts c 
      where a.taskno = b.taskno 
      and a.customerno = c.customerno 
      and c.accountno = b.accountno 
      and c.accountno = 1000 -- nothing returned for 1100 

這是一切都很好,但項目表並不總是可靠的。它可以說只有在任務表中找到的任務的90%。所以當任務未在項目表中發現這種情況下,我想從任務表,像accountno 3000(這意味着我將不得不customerno去,不會有accountno的粒度級別加入。但它是確定) 。但是當在這個項目中找到這個accountno時,我希望它被使用,因爲它有accountno,這給了我沒有與確切accountno關聯的taskno。因此,我將左外部聯接用於包含任務的項目。

這工作perfectly-

  select a.taskno 
      from tasks a, items b, accounts c 
      where a.taskno = b.taskno(+) 
      and a.customerno = c.customerno 
      and c.accountno = nvl(b.accountno, c.accountno) 
      and c.accountno = 3000 -- will return taskno 3 


      select a.taskno 
      from tasks a, items b, accounts c 
      where a.taskno = b.taskno(+) 
      and a.customerno = c.customerno 
      and c.accountno = nvl(b.accountno, c.accountno) 
      and c.accountno = 1000 --returns 1 and nothing returned for 1100 

我的問題是我有構造正確的查詢這裏 - 特別是我在哪裏聯用NVL項目以帳戶的一部分?這是預期的方式嗎?或者這是一個奇怪的回合嗎?

+2

好,你將會在這裏告訴你的第一件事是:使用ANSI連接語法! – sstan

+1

即使Oracle建議停止使用專有的'(+)'在where子句中使用隱式外連接,並使用明確的'LEFT JOIN'(或'RIGHT JOIN')運算符。 –

+0

我不明白你爲什麼要加入'items'表,如果你只從'tasks'表中進行選擇,並且通過'accounts'表字段進行過濾,並且兩個表都可以連接。爲什麼你需要在查詢中包含'items'?除非你也從'items'中選擇信息,但是你沒有顯示。 – sstan

回答

1

就像你說的,你的查詢做的工作,而且是相當高明。但很難閱讀和理解,部分原因是因爲使用了連接語法。使用ANSI加入翻譯,我們得到:

select t.taskno 
    from accounts a 
    join tasks t 
    on t.customerno = a.customerno 
    left join items i 
    on i.taskno = t.taskno 
where a.accountno = 1100 
    and a.accountno = nvl(i.accountno, a.accountno) 

我仍然覺得目的不是很清楚。

就個人而言,我會重寫查詢,移動左邊的邏輯not exists條款,而不是裏面加入。在我看來,它更好地表達了意圖,而且它的工作原理也是如此。

在ANSI連接語法:

select t.taskno 
    from accounts a 
    join tasks t 
    on t.customerno = a.customerno 
where a.accountno = 1100 
    and not exists (select null 
        from items i 
        where i.taskno = t.taskno 
         and i.accountno <> a.accountno) 

遺留同一查詢連接語法,如果它可以幫助你更好地理解(但儘量從這個語法,如果可能的話移開):

select t.taskno 
    from accounts a, tasks t 
where a.accountno = 1100 
    and t.customerno = a.customerno 
    and not exists (select null 
        from items i 
        where i.taskno = t.taskno 
         and i.accountno <> a.accountno)