简体   繁体   English

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

[英]How to bypass NULL in a Lookup Table using JOIN?

In SQL (SSMS), I am trying to do a lookup using a ranging table (similar to Point_Lookup below) and what I need is to bypass the NULL scenario. 在SQL(SSMS)中,我尝试使用范围表(类似于下面的Point_Lookup)进行查找,而我需要绕过NULL方案。

Firstly, please use below SQL codes to replicate the scenario in question: 首先,请使用下面的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)

I have tried below code to successfully join both tables and get the desired points EXCEPT when [Age] >= 50 (Since the Upper_Limit is showing NULL, the point from the lookup table is also showing NULL - desired result should be 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]

I have also tried replacing the NULL using ISNULL() but I realized this still does not JOIN both tables when [Age] >= 50 (not quite sure why). 我也尝试过使用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])

Is there a way to somehow only consider one condition --> (ppl.[Age] >= point.[Lower_Limit]) when [Age] >= 50 (without going into the NULL in Upper_Limit)? 当[年龄]> = 50(在Upper_Limit中不为NULL)时,是否有办法仅考虑一个条件->(ppl。[Age]> = point。[Lower_Limit])? Maybe somehow using CASE? 也许以某种方式使用CASE?

The expected result should show 6 Point when [Age] >= 50. Please help. [年龄]> = 50时,预期结果应显示6点。请提供帮助。

You can try using coalesce() function which will work like case when, so if point.[Upper_Limit] is null then it will consider later one 您可以尝试使用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])

If NULL means that the condition should be avoided then you can use an OR to write exactly this: 如果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])

In you attempt: 在您尝试:

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

If point.[Upper_Limit] is NULL then any addition will also be NULL , that's why it doesn't join correctly. 如果point.[Upper_Limit]NULL那么任何加法也将为NULL ,这就是为什么它不能正确连接的原因。 You should remove the point.[Upper_Limit] and just leave 1 + ppl.[Age] and it will work, but using the OR will be better for index usage (if any). 您应该删除该point.[Upper_Limit] ,只保留1 + ppl.[Age] ,它会起作用,但是使用OR 会更好地使用索引 (如果有)。

try this, 尝试这个,

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

The problem with this structure is that you can have lacks or overlaps in the ranges, also, in this case can be confusing which should be the correct point for a value equal to one of the limits... 这种结构的问题在于您可能会在范围内缺少或重叠,在这种情况下也可能会造成混淆,对于等于某个限制之一的值,这应该是正确的点...

I use to do it this way, with one single limit, the boundaries are defined by the previous and next records, and there is no way to have a lack of values out of the range 我使用这种方法,只有一个限制,边界是由前一条记录和下一条记录定义的,所以没有办法缺少超出范围的值

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM