2009-08-24 74 views
2

我有兩個表TABLE_ATABLE_B具有加入列作爲員工號碼EMPNOSQL左外部連接只有右側的一些行?

我想做一個正常的左外連接。但是,TABLE_B有一些軟刪除的記錄(status='D'),我希望這些被包含。爲了澄清,TABLE_B可能有活動記錄(status = null/a/anything)以及已刪除的記錄,在這種情況下,我不希望該員工在我的結果中。但是,如果在TABLE_B中只有員工的刪除記錄,我希望將該員工列入結果。我希望我明確了我的要求。 (我可以做很長的qrslt類的東西,並得到我想要的,但我認爲必須有一個更優化的方式來使用連接語法來做到這一點)。將不勝感激任何建議(即使沒有加入)。他的新手正在嘗試以下查詢而沒有想要的結果:

SELECT TABLE_A.EMPNO 
FROM TABLE_A 
LEFT OUTER JOIN TABLE_B ON TABLE_A.EMPNO = TABLE_B.EMPNO AND TABLE_B.STATUS<>'D' 

非常感謝任何幫助。

回答

0

啊污物,這顯然作品> <

SELECT TABLE_A.EMPNO 
FROM TABLE_A 
LEFT OUTER JOIN TABLE_B ON TABLE_A.EMPNO = TABLE_B.EMPNO 
where TABLE_B.STATUS<>'D' 

如果你們有任何額外的信息,雖然與附和,請隨意。

UPDATE: 看到這個問題後的某個時間,我想我會加入更多有用的信息:該鏈接有關於ANSI語法好消息 - http://www.oracle-base.com/articles/9i/ANSIISOSQLSupport.php

尤其是這部分從鏈接頁面信息:

可以向連接添加額外的過濾條件,以使用AND形成複雜的連接。當需要過濾條件來限制外部連接時,這些通常是必需的。如果這些過濾器條件放置在WHERE子句中,並且外部聯接爲篩選器列返回NULL值,則該行將被丟棄。如果過濾條件被編碼爲連接的一部分,則可以避免這種情況。

+0

這並不能滿足這個要求,包括行,其中的僱工*只有*已刪除記錄,是嗎? – Eric 2009-08-24 12:22:01

+0

其實它的確如此。員工只有在TAble_b中刪除了記錄(但在TABLE_A中有一行)。好的,當我到辦公室時,必須再次檢查。 – 2009-08-28 06:40:33

0

以下查詢會爲您提供未刪除的員工記錄,或者只有僱員只有已刪除的記錄。

select 
    a.* 
from 
    table_a a 
    left join table_b b on 
     a.empno = b.empno 
where 
    b.status <> 'D' 
    or (b.status = 'D' and 
     (select count(distinct status) from table_b where empno = a.empno) = 1) 

這是在ANSI SQL,但如果我知道你的RDBMS,我可以給一個更具體的解決方案,可能會更優雅。

+0

應該提到這一點,我使用的是Oracle 10g。 埃裏克,關於這種情況的澄清。 其中 b.status <>'D' 因爲這是一個左連接而不是左外連接,這實際上不包括那些沒有被刪除的行嗎? 或(b.status ='D'and (select table count from table_b where empno = a.empno)= 1) 我得到這個,table_b中只有已刪除的記錄,所以這個emp被包含。 – 2009-08-28 06:52:02

2

只是爲了澄清 - 應該出現TABLE_A的所有記錄,除非表B中有行,其他其他比'D'?

你需要在B中的至少一個非空列(我會用「B.ID」作爲一個例子,這種方法應該工作):

SELECT TABLE_A.EMPNO 
FROM TABLE_A 
LEFT OUTER JOIN TABLE_B ON 
    (TABLE_A.EMPNO = TABLE_B.EMPNO) 
    AND (TABLE_B.STATUS <> 'D' OR TABLE_B.STATUS IS NULL) 
WHERE 
    TABLE_B.ID IS NULL 

也就是說,扭轉您可能會想到的邏輯 - 只有在行數爲時排除 TABLE_A條目,然後在末尾使用IS NULL排除這些行的情況下,纔可以加入TABLE_B。這意味着只有那些不匹配(那些在TABLE_B中沒有行,或者只有'D'行)才被包括在內。

另一種可能是

SELECT TABLE_A.EMPNO 
FROM TABLE_A 
WHERE NOT EXISTS (
    SELECT * FROM TABLE_B 
    WHERE TABLE_B.EMPNO = TABLE_A.EMPNO 
    AND (TABLE_B.STATUS <> 'D' OR TABLE_B.STATUS IS NULL) 
) 
+0

其實我想讓狀態爲'd'的行包含在連接中。我不希望包含任何其他狀態。 想法是我只想從左邊的行或TABLE_A不在table_b中。 table_b中的一行被軟刪除意味着它根本不存在,不應該從我的查詢中排除。 (我希望我在讀你的回覆權) – 2009-08-28 06:35:03

0
SELECT A.*, B.* 
FROM 
    Table_A A 
    INNER JOIN Table_B B 
     ON A.EmpNo = B.EmpNo 
WHERE 
    NOT EXISTS (
     SELECT * 
     FROM Table_B X 
     WHERE 
      A.EmpNo = X.EmpNo 
      AND X.Status <> 'D' 
    ) 

我覺得這樣做的伎倆。左連接不是必需的,因爲您只想包含具有所有(至少一個)刪除行的員工。

0

這就是我對這個問題的理解。你需要只包括那些員工,其下面的任一爲真:

  • 僱員只(軟)在TABLE_B刪除的行;

  • 一名員工在TABLE_B中只有未刪除的行;

  • 員工在TABLE_B中根本沒有行。

換句話說,如果一個僱員都被刪除和在TABLE_B非刪除的行,省略僱員,否則包括它們。

這是我認爲它可以解決:

SELECT DISTINCT a.EMPNO 
FROM TABLE_A a 
    LEFT JOIN TABLE_B b1 ON a.EMPNO = b1.EMPNO 
    LEFT JOIN TABLE_B b2 ON b1.EMPNO = b2.EMPNO 
    AND (b1.STATUS = 'D' AND (b2.STATUS <> 'D' OR b2 IS NULL) OR 
     b2.STATUS = 'D' AND (b1.STATUS <> 'D' OR b1 IS NULL)) 
WHERE b2.EMPNO /* or whatever non-nullable column there is */ IS NULL 

另外,雖然你可以使用分組:

SELECT a.EMPNO 
FROM TABLE_A a 
    LEFT JOIN TABLE_B b ON a.EMPNO = b1.EMPNO 
GROUP BY a.EMPNO 
HAVING 0 IN (COUNT(CASE b.STATUS WHEN 'D' THEN 1 ELSE NULL END), 
      COUNT(CASE b.STATUS WHEN 'D' THEN NULL ELSE 1 END)) 
相關問題