如何使 OUTER JOIN 返回零而不是 NULL

Posted

技术标签:

【中文标题】如何使 OUTER JOIN 返回零而不是 NULL【英文标题】:How to make an OUTER JOIN return ZERO instead of NULL 【发布时间】:2017-10-28 04:28:26 【问题描述】:

我正在尝试在 SQL Server 上完成此操作。最简单的数据表结构如下所示。

Table:Blog

BlogID, Title
----------------
1, FirstBlog
23, Pizza

Table:User

UserID, Name
-------------------
123, james
444, John


Table:UserBlogMapping

UserBlogMappingID, BlogID,UserID
----------------------------------
1, 1, 123

我想在一个 SQL 查询中获取 FormID 和 UserBlogMappingID。如果提供的 UserID 不在映射表中,则返回零,否则返回有效的 userBlogMappingID。我正在尝试运行以下查询,但它不正确。

SELECT 
    B.BlogID, 
    BUM.BlogUserMappingID 
FROM 
    Blog AS B
        LEFT JOIN BlogUserMapping AS BUM ON B.BlogID = BUM.BlogID
WHERE 
    (B.BlogID = 23)  -- it exists in the table
    AND BUM.userID = 444 -- it is NOT in the mmaping table but i want a ZERO return in such case 

假设: 我们可以假设 WHERE 子句中提供的 UserID 始终是有效的 UserID 并且存在于 User 表中。

【问题讨论】:

【参考方案1】:

您可以将 userID=444 的条件放在 LEFT JOIN 的 ON 子句中。

还有一个 ISNULL 或一个 COALESCE 将 NULL 更改为 0。

使用表变量的示例:

declare @Blog table (BlogID int, Title varchar(30));
insert into @Blog (BlogId, Title) values
(1, 'FirstBlog'),
(23, 'Pizza');

declare @User table (UserID int, Name varchar(30));
insert into @User (UserID, Name) values
(123,'james'),
(444,'John');


declare @BlogUserMapping table (BlogUserMappingID int, BlogID int, UserID int);
insert into @BlogUserMapping (BlogUserMappingID, BlogID, UserID) values
(1, 1, 123),
(2, 23, 123),
(3, 1, 444);


-- Using the criteria in ON clause of the LEFT JOIN 
SELECT 
 B.BlogID, 
 ISNULL(BUM.BlogUserMappingID,0) as BlogUserMappingID
FROM @Blog B 
LEFT JOIN @BlogUserMapping BUM ON (B.BlogID = BUM.BlogID AND BUM.userID = 444)
WHERE B.BlogID = 23;

-- If there are more BlogId=23 with userID=444.
-- But only 1 row needs to be returned then you could also GROUP BY and take the maximum BlogUserMappingID
SELECT 
 B.BlogID, 
 MAX(ISNULL(BUM.BlogUserMappingID,0)) as BlogUserMappingID
FROM @Blog B 
LEFT JOIN @BlogUserMapping BUM ON (B.BlogID = BUM.BlogID AND BUM.userID = 444)
WHERE B.BlogID = 23
GROUP BY B.BlogID;

-- Using an OR in the WHERE clause would also return a 0. 
-- But it would also return nothing if the mapping table has a BlogID=23 with a userID<>444.
-- So not usefull in this case.
SELECT 
 B.BlogID, 
 ISNULL(BUM.BlogUserMappingID,0) as BlogUserMappingID
FROM @Blog B 
LEFT JOIN @BlogUserMapping BUM ON B.BlogID = BUM.BlogID
WHERE B.BlogID = 23
  AND (BUM.userID IS NULL OR BUM.userID = 444);

【讨论】:

您确定我们将在末尾保留“BUM.userID = 444”而不是在 LEFT JOIN 子句中吗? @LukStorms 不,它不会做同样的事情。这不是实现相同结果的替代方法。想想当LEFT JOIN 匹配时会发生什么,但它只匹配BUM.userID &lt;&gt; 444 所在的行。 @hvd 好的,我已经改了。应该在发布之前用映射表中的 23 进行测试。感谢您的建议。 @LukStorms 即使我根据您的建议更正了上述查询,如果“BlogUserMapping”表中有多个记录针对某个“BlogID”(不仅仅是匹配“BUM.UserID”的那个)。对于没有匹配的“BUM.UserID”,它可以正常工作。 @user1451111 好的,添加了一个使用 group by 的额外查询。我以为你想要所有带有特定 BlogID 和 UserID 的 BlogUserMapping。

以上是关于如何使 OUTER JOIN 返回零而不是 NULL的主要内容,如果未能解决你的问题,请参考以下文章

getElementsByTagName 返回零而不是 null 为啥

SQL中的join连接查询

返回带有零而不是空值的 Access 记录集

MySQL 数据库中 left outer join 和 left join 啥区别?

当参数作为整数传递时,Laravel 返回零而不是实际的单元格值

FULL OUTER JOIN 不返回所有表的内容