没有匹配 NULL 值的 PostgreSQL JOIN

Mic*_*ver 4 postgresql null join

我称这为我的“空之战”,因为我多年来一直在为这个问题而苦苦挣扎。

我有一个名为 的大表(250,000 多行,100 多列)People,另一个名为Stuff,其中可能包含也可能不包含相应的记录。我可以使用三列来查找可能的匹配项:人员 ID、电话号码或电子邮件地址。这些列中可能有也可能没有值,甚至可能包含空值。

我多年前为此编写的原始查询如下:

SELECT *
  FROM People
  LEFT OUTER JOIN Stuff
    ON People.PersonID = Stuff.PersonID
    OR People.CellNumber = Stuff.PhoneNumber
    OR People.Email = Stuff.WorkEmail;
Run Code Online (Sandbox Code Playgroud)

当我第一次尝试运行这个查询时,它在连接表中产生了数百万条记录,这完全不是我所期望的。经过几天的故障排除,我终于确定是空值和空单元格的存在导致了结果的巨大增长。对于那些可能不知道的人,PostgreSQL 以与其中包含数据的单元格相同的方式对待空值和空单元格。结果是它获取 People 表中带有空单元格的每条记录,并将它与 Stuff 表中带有空单元格的每条记录连接起来。它对空值和所有三个比较执行相同的操作。

我搜索了数周,但从未找到解决此问题的优雅或简单的方法,因此我最终不得不将其分解为一系列单独的查询,如下所示。

SELECT *
FROM People
    LEFT OUTER JOIN Stuff
      ON People.PersonID = Stuff.PersonID
    WHERE (People.PersonID != ''
      AND People.PersonID IS NOT NULL);
Run Code Online (Sandbox Code Playgroud)

将匹配的记录转储到临时表中,然后通过第二个查询运行不匹配的记录:

SELECT *
FROM People
    LEFT OUTER JOIN Stuff
      ON People.CellNumber = Stuff.PhoneNumber
    WHERE (People.CellNumber != ''
      AND People.CellNumber IS NOT NULL);
Run Code Online (Sandbox Code Playgroud)

将匹配的记录转储到临时表中,然后通过第三个查询运行剩余的不匹配记录:

SELECT *
FROM People
    LEFT OUTER JOIN Stuff
      ON People.Email = Stuff.WorkEmail
    WHERE (People.Email != ''
      AND People.Email IS NOT NULL);
Run Code Online (Sandbox Code Playgroud)

将结果(匹配和不匹配)转储到临时表中,然后继续。

多年来,我一直在使用这种非常不优雅的方法,并且没有任何问题。但是现在我需要修改这个脚本以适应业务需求的变化,我试图再次找到一个更简单的解决方案。当前方法的问题是,每当我必须对查询进行更改时,我都必须在代码中的多个位置进行更改,这会导致维护的噩梦。

在这次迭代中,我提出了以下几点:

SELECT *
  FROM People
  LEFT OUTER JOIN Stuff
    ON (People.PersonID = Stuff.PersonID
        WHERE People.PersonID != ''
          AND People.PersonID IS NOT NULL)
    OR (People.CellNumber = Stuff.PhoneNumber
        WHERE People.CellNumber != ''
          AND People.CellNumber IS NOT NULL)
    OR (People.Email = Stuff.WorkEmail)
        WHERE People.Email != ''
          AND People.Email IS NOT NULL);
Run Code Online (Sandbox Code Playgroud)

这看起来应该有效,但它在第一WHERE个子句中消失。

我在正确的轨道上吗?我怎样才能使这项工作?或者有没有另一种更好的方法?

必须有一种方法以与空值或空值不匹配的方式运行原始的三条件查询,但我还没有找到它。

狗走了!我要赢得这场空之战!(当然有你的帮助!)

Gor*_*off 11

Postgres 不“空”单元格与NULL值进行匹配。 NULL使用典型的比较运算符,与任何内容都不匹配。但是,空字符串将匹配空字符串。l

我怀疑你真的想要这样的东西:

SELECT p.*, COALESCE(sp.?, sc.?, se.?) as ?
FROM People p LEFT OUTER JOIN
     Stuff sp
     ON p.PersonID = sp.PersonID LEFT OUTER JOIN
     Stuff sc
     ON p.CellNumber = sc.PhoneNumber AND sp.personID IS NULL LEFT OUTER JOIN
     stuff se
     ON p.Email = se.WorkEmail AND sc.personID is null;
Run Code Online (Sandbox Code Playgroud)

这将为 中的每一行获取三个表中的第一个匹配项people


Hal*_*Ali 5

如果布尔表达式中的右侧字段是空字符串,则将它们视为空字符串,使用NULLIF函数,然后对于左右表至少有 1 个'' == ''.

SELECT *
  FROM People
  LEFT OUTER JOIN Stuff
    ON People.PersonID = NULLIF(Stuff.PersonID, '')
    OR People.CellNumber = NULLIF(Stuff.PhoneNumber, '')
    OR People.Email = NULLIF(Stuff.WorkEmail, '');
Run Code Online (Sandbox Code Playgroud)