【问题标题】:PostgreSQL: Match Email Addresses With or Without SubdomainsPostgreSQL:匹配带有或不带有子域的电子邮件地址
【发布时间】:2021-04-07 03:27:19
【问题描述】:

场景

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

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

如何实现?

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

【问题讨论】:

  • 你在哪里匹配这些?使用原始查询?网络服务器后端?
  • 我将数据集导入笔记本电脑上的 PostgreSQL 数据库,并针对它们运行一堆 SQL 以进行深入分析和报告。

标签: postgresql pattern-matching email-address


【解决方案1】:

在我的脑海中,您可以在比较所有电子邮件地址之前从所有电子邮件地址中删除子域(即仅比较电子邮件名称和域)。像这样的:

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

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 \1
    .*?             consume content up, but not including
    ([^.]+\.[^.]+)  final domain only (e.g. google.com)
$                   end of the email

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

【讨论】:

  • 天哪,你给了我明天要做的功课!这是我需要的,但现在我必须学习它是如何工作的!几十年来,我一直在 'nix 系统中使用正则表达式,但这表明我只触及了皮毛!
  • 我打算先在我的真实数据上尝试一下,但你的演示确实表明它有效。非常感谢这个优雅的解决我的问题!
【解决方案2】:

这样的事情怎么样?

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
    )
  );

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-03-20
    • 2012-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多