【问题标题】:How to use write a SQL join when there exists empty cell in the join column?当连接列中存在空单元格时,如何使用编写 SQL 连接?
【发布时间】:2022-01-27 21:28:27
【问题描述】:

架构:

CREATE TABLE PRODUCT
(
    PRODUCTID INT, 
    PRODUCTNAME VARCHAR(100), 
    PRODUCTUSER VARCHAR(100)
);

CREATE TABLE USER
(
    USERID INT, 
    USERNAME VARCHAR(100),
    USEREMAIL VARCHAR(100)
);

INSERT INTO PRODUCT(PRODUCTID,PRODUCTNAME,PRODUCTUSER) 
VALUES (1, 'Product1', 'Chen'), (2, 'Product2', 'Bob'), 
       (3, 'Product3', ''), (4, 'Product4', '');

INSERT INTO USER (USERID, USERNAME, USEREMAIL) 
VALUES (1, 'Chen', 'chen@email.com'),
       (2, 'Bob', 'bob@email.com'),
       (3, 'Paul', 'paul@email.com'),
       (4, '', ''), (5, '', '');

产品表:

ProductID  ProductName  ProductUser
------------------------------------
1          Product1     Chen
2          Product2     Bob
3          Product3      
4          Product4 

用户表:

UserID  UserName  UserEmail
--------------------------------
1       Chen      chen@email.com
2       Bob       bob@email.com
3       Paul      paul@email.com
4    
5

我想加入产品和用户表以获取所有产品名称和用户名(如果可用)作为输出。挑战在于公共字段 Product.ProductUser 和 User.UserName 都包含空值,如上例所示。我知道这不是一个好的架构设计,但我无法更改架构,因为它超出了我的控制范围。

预期输出:

PROCUTNAME   USERNAME
----------------------
Product1     Chen
Product2     Bob
Product3
Product4

示例查询 1:

SELECT PRODUCTNAME, USERNAME
FROM PRODUCT P
JOIN USER U
ON P.PRODUCTUSER=U.USERNAME

上面的查询是一个内部连接,因此返回 Product3 和 Product4 的重复项,因为连接为空。添加 WHERE 子句 ProductUser'' 会导致排除 Product3 和 Product4。

通常,如果 ProductUser 为 NULL 而不是空,那么我知道 LEFT JOIN 将是解决方案。我想我理解在 LEFT JOIN 的 ON 子句和 WHERE 子句中使用条件的区别。

因此尝试在 ON 子句中使用条件进行左连接:

SELECT PRODUCTNAME, USERNAME
FROM PRODUCT P
LEFT JOIN USER U
ON P.PRODUCTUSER=U.USERNAME AND P.PRODUCTUSER<>''

因此,上述查询首先根据 ON 子句中的给定条件进行内部连接,然后从产品表中提取所有其他行并将用户名设置为空。 (或者换句话说,它首先列出所有产品,然后加入那些满足 ON 标准的记录。)

这给了我预期的输出。但我不确定我的方法是否正确,所以尝试另一种方法:

SELECT PRODUCTNAME, USERNAME
FROM PRODUCT P
LEFT JOIN (SELECT * FROM USER WHERE USERNAME<>'') U
ON P.PRODUCTUSER=U.USERNAME

这也有效。

在 ON 子句中使用条件左连接是解决问题的正确方法吗?

【问题讨论】:

  • 这两个查询之间的区别完全没有。它们将产生相同的查询计划。无论您做什么,都不要将WHERE 放在外部WHERE 中,只能放在ON 或内部WHERE 中。他们是'' 还是NULL
  • 你为什么不能只做SELECT PRODUCTNAME, USERNAME FROM PRODUCT?它准确地返回您请求的预期输出..
  • 用户表中还有几个我还想要的值

标签: sql sql-server tsql


【解决方案1】:

你可以通过分组来删除重复项吗?

declare @prod TABLE (PRODUCTID INT, PRODUCTNAME VARCHAR(100), PRODUCTUSER VARCHAR(100));

declare @user table (USERID INT, USERNAME VARCHAR(100),USEREMAIL VARCHAR(100));

INSERT INTO @prod(PRODUCTID,PRODUCTNAME,PRODUCTUSER) values (1,'Product1','Chen'),
(2,'Product2','Bob'),(3,'Product3',''),(4,'Product4','');

INSERT INTO @user(USERID,USERNAME,USEREMAIL) VALUES (1,'Chen','chen@email.com'),
(2,'Bob','bob@email.com'),(3,'Paul','paul@email.com'),
(4,'',''),(5,'','');


select * from @prod
select * from @user

select 
    p.ProductId,
    p.ProductName,
    u.USERNAME
FROM @prod p
    left join @user u on p.PRODUCTUSER = u.USERNAME
group by
    p.PRODUCTID,
    p.PRODUCTNAME,
    u.USERNAME

【讨论】:

    【解决方案2】:
    select
        main.PRODUCTNAME
        , case
            when sub.USERNAME is null
            then ''
            else sub.USERNAME
        end USERNAME
    
    from #PRODUCT main
        left join
        #USER sub
        on main.PRODUCTUSER = sub.USERNAME
            and sub.USERNAME like '%[A-Za-z]%'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-24
      • 1970-01-01
      • 1970-01-01
      • 2019-12-25
      • 1970-01-01
      • 1970-01-01
      • 2020-10-02
      • 1970-01-01
      相关资源
      最近更新 更多