簡體   English   中英

Teradata SQL中的同一表的LEFT JOIN WHERE RIGHT IS NULL

[英]LEFT JOIN WHERE RIGHT IS NULL for same table in Teradata SQL

我有一張有51條記錄的表。 表結構如下所示:

ack_extract_id query_id cnst_giftran_key field1 value1

現在ack_extract_ids可以為8,9。 我想檢查是否存在extractran_id 9而不是8中的giftran鍵。

我試過的是

            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條記錄。 理想情況下,其中right為null的左連接應該返回右側表中不存在cnst_giftran_key的記錄,對嗎?

我在這里想念什么?

當您在where子句(在您的情況下為ack_flextable2.ack_extract_id中測試來自左聯接表的列時,您將強制該ack_flextable2.ack_extract_id表現為內部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

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

從您的評論到Joe Stefanelli的回答,我認為您不完全了解外部聯接中WHERE和ON的問題。 因此,讓我們看一個例子。

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

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為null的記錄。 好吧,ID顯然是表的主鍵,並且永遠不能為空,因此我們在這里保留的只是外部聯接結果,其中較新的數據只是包含空值的虛擬記錄。 因此,我們確切地獲得了不存在新訂單的訂單。

談論巨大的中間結果:這比第一個查詢快嗎? 好吧,不應該。 實際上,第一個查詢應該運行得更快或更快。 優秀的DBMS將會了解這一點,並為兩個查詢制定相同的執行計划。 一個相當年輕的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永遠不會為真。 最終結果將為空-這正是查詢所發生的情況。

您可以嘗試使用以下查詢:

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;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM