2017-06-28 107 views
2

我繼承了一個使用左連接的查詢。查詢所做的一件事就是刪除所有歸檔記錄,即archived ='Y'。這是查詢的外觀:SQL空值連接問題

select P.firstname, E.entityid, C.committeeid, L.locationname 
    from Pract P 
    left join Committee C 
    on P.commiteeid = C.committeeid 
    and c.archived = 'N' 
    left join Entity E 
    on P.entityid = E.EntityID 
    and e.archived = 'N' 
    left join Location L 
    on E.location = L.location 
    and l.archived = 'N' 

結果應該只返回那裏存檔<>「Y」的記錄。我想用把過濾器與「上」的問題是,它會返回其中c.archived =「N」,只是把一個空的存檔領域的記錄,這是不正確的:

FirstName EntityID  CommitteeId 
    John   55   null 

如果c.archived ='Y',則記錄不應顯示。

我相信歸檔的過濾器應在where子句中,像這樣的:

select firstname, entityid, committeeid 
    from Pract P 
    left join Committee C 
    on P.commiteeid = C.committeeid 
    left join Entity E 
    on P.entityid = E.entityid 
    left join Location L 
    on E.Locationid = L.locationid 
    where c.archived = 'N' 
    and e.archived = 'N' 
    and l.archived = 'N' 

我發現的問題是,有些情況,其中來自委員會存檔的字段爲空(這不是一個' Y'或'N')。使用我的解決方案錯誤地消除了記錄,因爲空<>'N.'

如果我試試這個:

where c.archived <> 'Y' 

它不工作,我猜是因爲NULL不評價任何東西。

如果我試試這個:

where (c.archived = 'N' or c.archived is null) 

這是行不通的,因爲它現在帶回所造成的左邊的空記錄加入。我不能用左連接替換內連接,因爲這會排除c.committeeid爲空的記錄。

我只想將歸檔的記錄帶回<>'Y',其中包括字段爲空的那些記錄。

需要明確的是,這是在表中的記錄可以是什麼樣子:

FirstName EntityID Archived 
    John   55   Y 
    Tom   56   NULL 
    Rob   57   N 

在這種情況下我想要返回的記錄是這樣的:

Tom    56   NULL 
    Rob    57   N 

約翰將被淘汰因爲存檔=「是」。

是否有另一種方法可以做到這一點?

+0

*「我想用把過濾器的一個問題 」上「 是它會返回一個記錄,其中c.archived ='N'並且只在歸檔字段中放置一個null,正確。「*它確實如此。您正在進行**左連接**,這意味着**左**表中的所有元素都應包含在結果中。由於在符合該過濾器的右表上找不到匹配,因此您會爲這些列獲得空值。如果你只想在右**表中匹配匹配的元素,那麼做一個**內連接**。 – derloopkat

+0

我繼承了這段代碼,並試圖使其正常工作。我相信最初的開發人員並沒有以正確的方式寫這篇文章。我不希望記錄返回如果「archived ='N',所以左連接是不合適的,但我希望記錄返回,如果表中的」歸檔「字段是空的我不能做一個內部聯接,因爲有如果C.committeeid爲空,我不能在「P.commiteeid = C.committeeid」上執行,我需要它僅返回一個實例,其中的連接右側的表中的字段爲空。記錄「歸檔」>「Y」。 – jackstraw22

+0

http://wiki.lessthandot.com/index.php/WHERE_conditions_on_a_LEFT_JOIN – HLGEM

回答

0

如果我理解正確的話,你想用另一個領域的where子句中的過濾:

select firstname, entityid, committeeid -- this will return an error on committeeid 
from Pract P left join 
    Committee C 
    on P.commiteeid = C.committeeid and 
     (c.archived <> 'Y' or c.archived is null) 
where c.committeeid is not null; 

您可能還可以與exists做到這一點更容易:

select p.* 
from Pract P 
where not exists (select 1 
        from Committee C 
        where P.commiteeid = C.committeeid and 
         c.archived = 'Y' 
       ); 

這自動處理NULL值。

+0

我的查詢實際上有大約15個左連接,並從每個表中拉出字段。我對它進行了更新,以便通過其中的一些連接提供更準確的表示。 – jackstraw22

-1

解決方案取決於您想如何處理左連接的NULL值。如果NULL表示沒有存檔,那麼

select firstname, entityid, committeeid 
    from Pract P 
    left join Committee C 
    on P.commiteeid = C.committeeid 
    left join Entity E 
    on P.entityid = E.entityid 
    left join Location L 
    on E.Locationid = L.locationid 
    where (c.archived = 'N' OR c.archived IS null) 
    and (e.archived = 'N' OR e.archived IS null) 
    and (l.archived = 'N' OR l.archived IS NULL) 
+0

這會將左連接更改爲內連接,因此不建議使用。 – HLGEM

+0

@HLGEM你在說什麼?這是怎麼變成內連接 – domenicr

+0

我在我給的例子中試過這個。此方法消除歸檔字段爲NULL的記錄。 – jackstraw22

0

我相信你正在尋找這個版本。您只需從您擁有的內容開始,然後修改連接條件以覆蓋不等於Y且值爲NULL的值。

select firstname, entityid, committeeid 
from Pract P 
left join Committee C 
on P.commiteeid = C.committeeid 
and (c.archived <> 'Y' OR c.archived IS NULL) 

然後,如果您只需要在委託表中記錄的項目。你把它放在WHERE子句中。

WHERE P.commiteeeid = C.commiteeid 

但它只會模仿INNER JOIN。

您與比較NULL的問題是,您不能使用<>來測試NULL值。如果你想要有NULL值的記錄,你必須明確地測試IS NULL

所以你更新的查詢看起來像:

select P.firstname, E.entityid, C.committeeid, L.locationname 
from Pract P 
left join Committee C 
on P.commiteeid = C.committeeid 
and (c.archived <> 'Y' OR c.archived IS NULL) 
left join Entity E 
on P.entityid = E.EntityID 
and (e.archived <> 'Y' OR e.archived IS NULL) 
left join Location L 
on E.location = L.location 
and (l.archived <> 'Y' OR l.archived IS NULL) 

如果你只值「Y」「N」和NULL,那麼你也可以使用

and (c.archived = 'N' OR c.archived IS NULL) 

只是可以肯定我們瞭解對方這裏是您查詢

create table Pract (firstname varchar(20), cid int) 
create table comt (cid int, archived varchar(1)) 

insert into Pract values ('Tom',1),('Adam',2),('Mark',3),('Bob',4) 
insert into comt values (1,'Y'), (2,'N'), (3,NULL) 

小例子 -

select firstname, P.cid, C.cid, C.archived 
from Pract P 
LEFT join comt C 
on P.cid = C.cid 
and (c.archived <> 'Y' OR c.archived IS NULL) 

有了結果

firstname cid cid archived 
1  Tom 1 NULL NULL 
2  Adam 2 2  N 
3  Mark 3 3  NULL 
4  Bob 4 NULL NULL 

或用INNER JOIN

select firstname, P.cid, C.cid, C.archived 
from Pract P 
INNER join comt C 
on P.cid = C.cid 
and (c.archived <> 'Y' OR c.archived IS NULL) 

有了結果

firstname cid cid archived 
1 Adam 2 2 N 
2 Mark 3 3 NULL 
+0

只有存檔值='Y'時,我才需要刪除記錄。如果委託表中的存檔值爲NULL,那麼我需要它返回一個空值。在這種情況下,INNER JOIN將刪除整個記錄。 – jackstraw22

+0

好的,我希望我終於明白了。只有在存檔<> Y時才需要練習和共享,其中包括NULL值。這是什麼應該返回。 –

+0

@ Marek - 是的。我再次更新了該問題,以顯示需要返回的內容。 – jackstraw22