PostgreSQL:匹配带或不带子域的电子邮件地址

PostgreSQL: Match Email Addresses With or Without Subdomains

场景

在其历史的大部分时间里,我的公司在电子邮件地址中使用子域,主要是按州划分,但其他公司有分部子域。我们的一些示例包括:

mo.widgits.com
sd.widgits.com
va.widgits.com
nhq.widgits.com
gis.widgits.com
tech.widgits.com

...等等。

新范式

几年前,高层管理人员决定,他们希望我们所有人成为一个幸福的家庭;作为这种文化调整的一部分,他们将每个人的电子邮件地址更改为单一域,格式为 firstname.lastname@widgits.com.

目前的挑战

在我们的许多公司数据库中,我们发现混合使用旧格式和新格式的记录。例如,同一个人可能在员工系统中有 porky.pig@widgits.com,在培训系统中有 porky.pig@in.widgits.com。我需要在各种系统中匹配个人,无论该系统中使用哪种格式的电子邮件。

期望匹配

porky.pig@in.widgits.com = porky.pig@widgits.com -> true
mary.poppins@widgits.com = mary.poppins@nhq.widgits.com -> true
bob.baker@widgits.com = bob.barker@gis.widgits.com -> false

如何实现?

是否有正则表达式模式可用于匹配电子邮件地址,无论它们是哪种格式?还是我需要在尝试匹配它们之前手动提取子域?

我没想到,您可以在比较所有电子邮件地址之前去掉子域(即只比较电子邮件名称和域)。像这样:

SELECT *
FROM emails
WHERE REGEXP_REPLACE(email1, '^(.*@).*?([^.]+\.[^.]+)$', '') =
      REGEXP_REPLACE(email2, '^(.*@).*?([^.]+\.[^.]+)$', '');

Demo

数据:

WITH emails AS (
    SELECT 'porky.pig@in.widgits.com' AS email1, 'porky.pig@widgits.com' AS email2 UNION ALL
    SELECT 'mary.poppins@widgits.com', 'mary.poppins@nhq.widgits.com' UNION ALL
    SELECT 'bob.baker@widgits.com','bob.barker@gis.widgits.com'
)

这里是对所用正则表达式模式的解释:

^                   start of the email
    (.*@)           match email name including @ in 
    .*?             consume content up, but not including
    ([^.]+\.[^.]+)  final domain only (e.g. google.com)
$                   end of the email

然后,我们替换为 以有效删除任何子域组件。

这样的怎么样?

SELECT 
  * 
FROM 
  (
    SELECT 
      table1.email, 
      table2.email, 
      SPLIT_PART(table1.email, '@', 1) AS table1_username, 
      SPLIT_PART(table2.email, '@', 1) AS table2_username, 
      SPLIT_PART(table1.email, '@', 2) AS table1_domain, 
      SPLIT_PART(table2.email, '@', 2) AS table2_domain 
    FROM 
      table1 CROSS 
      JOIN table2
  ) S 
WHERE 
  (
    table1_username = table2_username 
    AND (
      table1_domain like '%.' || table2_domain 
      OR table2_domain like '%.' || table1_domain
    )
  );