如何使用JOIN绕过查找表中的NULL?

时间:2019-02-13 08:04:37

标签: sql sql-server

在SQL(SSMS)中,我正在尝试使用范围表(类似于下面的Point_Lookup)进行查找,而我需要绕过NULL方案。

首先,请使用下面的SQL代码复制有问题的方案:

-- Code for People Data --
Create table #People ([Name] varchar(50) null,Age int null)

Insert into #People VALUES
('George' , 30),
('Clooney' , 18),
('Sandra' , 44),
('Bullock' , 15),
('Adam' , 100)

-- Code for Point_Lookup Data--
Create table #Point_Lookup ([Lower_Limit] int null, [Upper_Limit] int null, [Point] int null)

Insert into #Point_Lookup VALUES
(0, 10, 1),
(10, 20, 2),
(20, 30, 3),
(30, 40, 4),
(40, 50, 5),
(50, NULL, 6)

我尝试下面的代码成功连接两个表并获得期望的点,但[Age]> = 50时除外(由于Upper_Limit显示NULL,因此查找表中的点也显示NULL-期望的结果应为6 )。

Select ppl.*, point.[Point]
from #People as ppl
left join #Point_Lookup as point 
on ppl.[Age] >= point.[Lower_Limit] and 
ppl.[Age] < point.[Upper_Limit]

我也尝试过使用ISNULL()替换NULL,但是我意识到当[Age]> = 50(不太清楚为什么)时,这仍然不能联接两个表。

Select ppl.*, point.[Point]
from #People as ppl
left join #Point_Lookup as point 
on ppl.[Age] >= point.[Lower_Limit] 
and ppl.[Age] < isnull(point.[Upper_Limit], point.[Upper_Limit] + 1 + ppl. 
[Age])

当[Age]> = 50(在Upper_Limit中不为NULL)时,是否有办法仅考虑一个条件->(ppl。[Age]> = point。[Lower_Limit])?也许以某种方式使用CASE?

[年龄]> = 50时,预期结果应显示6点。请帮忙。

4 个答案:

答案 0 :(得分:3)

您可以尝试使用coalesce()函数,该函数在某些情况下会起作用,因此,如果point。[Upper_Limit]为null,则它将考虑稍后使用

    Select ppl.*, point.[Point]
    from #People as ppl
    left join #Point_Lookup as point 
    on ppl.[Age] >= point.[Lower_Limit] 
    and ppl.[Age] < coalesce(point.[Upper_Limit], point.[Lower_Limit] + 1 + ppl. 
    [Age])

答案 1 :(得分:3)

如果NULL意味着应该避免该情况,那么您可以使用OR来精确地写成这样:

Select 
    ppl.*, 
    point.[Point]
from 
    #People as ppl
    left join #Point_Lookup as point on 
        ppl.[Age] >= point.[Lower_Limit] and 
        (point.[Upper_Limit] IS NULL OR ppl.[Age] < point.[Upper_Limit])

尝试:

isnull(point.[Upper_Limit], point.[Upper_Limit] + 1 + ppl.[Age])

如果point.[Upper_Limit]NULL,那么任何加法也将是NULL,这就是为什么它不能正确加入的原因。您应该删除point.[Upper_Limit]并离开1 + ppl.[Age],它会起作用,但是使用OR 会更好地使用索引(如果有)。

答案 2 :(得分:0)

尝试一下

Select ppl.*,
(select top 1 point from #Point_Lookup where ppl.Age>=Lower_Limit and ppl.Age<=(case when Upper_Limit is null then ppl.Age else Upper_Limit end) ) from #People as ppl

答案 3 :(得分:0)

这种结构的问题是,您可能会在范围内缺少或重叠,在这种情况下,也可能会造成混淆,对于等于某个限制之一的值,应该是正确的点...

我经常这样做,只有一个限制,边界是由上一条和下一条记录定义的,没有办法缺少超出范围的值

Create table #People ([Name] varchar(50) null,Age int null)

Insert into #People VALUES
('George' , 30),
('Clooney' , 18),
('Sandra' , 44),
('Bullock' , 15),
('Adam' , 100),
('Lio' , 4)
-- Code for Point_Lookup Data--
Create table #Point_Lookup ([Limit] int not null,[Point] int null)

Insert into #Point_Lookup VALUES
(0, 1),
(10, 2),
(20, 3),
(30, 4),
(40, 5),
(50, 6)

SELECT *
FROM
#People P
CROSS APPLY (
    SELECT TOP 1 Point 
    FROM #Point_Lookup L 
    WHERE P.Age >= L.Limit
    ORDER BY Limit DESC
) L

drop table #people
drop table #Point_Lookup