【问题标题】:How to make an OUTER JOIN return ZERO instead of NULL如何使 OUTER JOIN 返回零而不是 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 表中。

【问题讨论】:

    标签: sql sql-server select outer-join


    【解决方案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。
    猜你喜欢
    • 2012-10-28
    • 1970-01-01
    • 2010-11-05
    • 2021-09-13
    • 1970-01-01
    • 1970-01-01
    • 2018-05-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多