2016-01-21 35 views
1

我有一張包含51條記錄的表。表結構看起來像下面:對於Teradata中的同一表,左加入權爲NULL NULL

ack_extract_idquery_idcnst_giftran_key字段1值1

現在ack_extract_ids可以8,9。 我想檢查giftran按鍵,在那裏爲extract_id 9和8

不在那裏,我試過什麼

  SELECT * 
      FROM ddcoe_tbls.ack_flextable ack_flextable1 
      INNER JOIN ddcoe_tbls.ack_main_config config 
       ON ack_flextable1.ack_extract_id = config.ack_extract_id 
      LEFT JOIN ddcoe_tbls.ack_flextable ack_flextable2 
       ON ack_flextable1.cnst_giftran_key = ack_flextable2.cnst_giftran_key 
      WHERE ack_flextable2.cnst_giftran_key IS NULL 
      AND config.ack_extract_file_nm LIKE '%Dtl%' 
       AND ack_flextable2.ack_extract_id = 8 
       AND ack_flextable1.ack_extract_id = 9 

但它返回我0的記錄。理想情況下,右側爲空的左連接應返回右側表中不存在cnst_giftran_key的記錄,對吧?

我在這裏錯過了什麼?

+0

請編輯您的問題,並提供樣本數據和預期的結果。我得到的是查詢,但不是你真正想做的。 –

+2

爲什麼你使用反連接技巧?使用「EXISTS」或「IN」進行直接查詢有問題嗎? –

+0

當然。我也會和他們一起去。 – StrugglingCoder

回答

3

當您在where子句(ack_flextable2.ack_extract_id)中測試左連接表中的列時,您強制該連接表現得好像是內連接一樣。相反,將該測試移動到連接條件的一部分。

然後要找到缺少該值的記錄,請在where子句中測試NULL鍵。

 SELECT * 
     FROM ddcoe_tbls.ack_flextable ack_flextable1 
     INNER JOIN ddcoe_tbls.ack_main_config config 
      ON ack_flextable1.ack_extract_id = config.ack_extract_id 
     LEFT JOIN ddcoe_tbls.ack_flextable ack_flextable2 
      ON ack_flextable1.cnst_giftran_key = ack_flextable2.cnst_giftran_key 
       AND ack_flextable2.ack_extract_id = 8 
     WHERE ack_flextable2.cnst_giftran_key IS NULL 
     AND config.ack_extract_file_nm LIKE '%Dtl%' 
      AND ack_flextable1.ack_extract_id = 9 
      AND ack_flextable2.cnst_giftran_key IS NULL 
+0

感謝您的幫助和解釋。那麼每當我執行一個左連接時,我總是應該將測試部分從右表(在這種情況下是flextable2)移動到連接條件本身?左表(flextable1)列可以成爲Where子句的一部分? – StrugglingCoder

+0

這是關於你的結果包含什麼。每個結果記錄都包含FROM和INNER JOIN中所列表中的數據。但是來自外部連接表的數據可以或不可以在那裏。如果匹配,則數據來自表格,如果不匹配,則只是填充了空值的虛擬數據。因此,在LEFT(或右或全部)OUTER JOIN中,ON子句*必須包含所有連接標準,否則您將獲得實際需要假人的記錄。當你在你的WHERE子句中添加條件時,例如'AND ack_flextable2.ack_extract_id = 8',這對虛擬記錄來說永遠不會是真的,所以你可以刪除它們。 –

+0

有關外部連接的WHERE/ON的詳細說明,請參閱以下手冊:http://www.info.teradata.com/HTMLPubs/DB_TTU_15_10/SQL_Reference/B035_1146_151K/ch02.022.48.html特別閱讀*外部聯接案例研究* – dnoeth

1

這是沒有回答,只是一種解釋

從對喬·斯特凡內利的回答您的評論我猜你不完全瞭解哪裏,並可在外部連接的問題。我們來看一個例子。

我們正在尋找所有供應商的最後訂單,即供應商沒有更新訂單的訂單記錄。

select * 
from order 
where not exists 
(
    select * 
    from order newer 
    where newer.supplier = order.supplier 
    and newer.orderdate > order.orderdate 
); 

這是直截了當的;該查詢與我們剛纔放入的單詞相匹配:查找不存在針對同一供應商的較新訂單的訂單。

與反連接模式同樣的查詢:

select order.* 
from order 
left join order newer on newer.supplier = order.supplier 
         and newer.orderdate > order.orderdate 
where newer.id is null; 

在這裏,我們加入他們所有的新訂單每一個訂單,因此很可能創造了巨大的中間結果。通過左外部連接,我們確保在供應商沒有更新的訂單時附上虛擬記錄。然後最後我們用WHERE子句掃描中間結果,只保留附加記錄的ID爲空的記錄。那麼,ID顯然是表的主鍵,並且不能爲空,所以我們在這裏保留的只是外連接的結果,其中較新的數據只是包含空值的虛擬記錄。因此,我們可以得到沒有新訂單的訂單。

談論一個巨大的中間結果:這怎麼能比第一個查詢更快?那麼,它不應該。第一個查詢應該實際上運行速度相同或更快。一個好的數據庫管理系統將會看到這一點,併爲兩個查詢制定相同的執行計劃。然而,一個相當年輕的DBMS可能會更快地執行反連接。這是因爲開發人員在連接技術方面付出了很多努力,因爲在每個查詢中都需要這些技術,並且還不關心IN和EXISTS。在這種情況下,可能會遇到NOT IN或NOT EXISTS的性能問題,並使用反連接模式。

現在是到WHERE/ON問題:

select order.* 
from order 
left join order newer on newer.orderdate > order.orderdate 
where newer.supplier = order.supplier 
and newer.id is null; 

這看起來幾乎與以前一樣,但有些標準已就移動到哪裏。這意味着外連接得到不同的標準。以下是發生的情況:無論哪個供應商,每個訂單都可以找到所有新訂單‐!所以最後一個訂單日期的所有訂單都會獲得一個外連接虛擬記錄。但是,在WHERE子句中,我們刪除供應商不匹配的所有對。請注意,外連接記錄對於newer.supplier包含NULL,所以newer.supplier = order.supplier對於它們來說從不是真的;他們被刪除。但是,如果我們刪除所有外連接的記錄,我們會得到與香草內連接完全相同的結果。當我們將外連接標準放在WHERE子句中時,我們將外連接轉換爲內連接。因此,查詢可重新寫爲

select order.* 
from order 
inner join order newer on newer.orderdate > order.orderdate 
where newer.supplier = order.supplier 
and newer.id is null; 

而且在FROM和INNER JOIN不要緊的標準是否在ON或WHERE表;這是一個可讀性問題,因爲這兩個標準將同樣得到應用。

現在我們看到newer.id is null永遠不會是真的。最終結果將爲空‐這正是您的查詢所發生的情況。

+1

很好的解釋,但這個例子是Teradata的最壞情況(我在MySQL支持子查詢之前主要看到了這一點)。儘管擁有一個35歲的成熟優化器加入非平等表現非常糟糕,因爲Teradata是一個並行DBMS。在所有情況下,'NOT EXISTS'都會勝過'LEFT JOIN WHERE IS NULL'。但一個很好的'order_date =(SELECT MAX(order_date)...'好得多,通常最好的是'RANK/ROW_NUMBER'(自1998年以來,即使在添加到標準SQL之前,它也受到支持) – dnoeth

+0

感謝您提供了這麼好的解釋。 – StrugglingCoder

0

你可以用這個查詢嘗試:

select * from ddcoe_tbls.ack_main_config 
where cnst_giftran_key not in 
    (
    select cnst_giftran_key from ddcoe_tbls.ack_main_config 
    where ack_extract_id = 8 
) 
and ack_extract_id = 9;