【问题标题】:Left join with string function?用字符串函数左连接?
【发布时间】:2017-11-29 18:24:21
【问题描述】:

我需要左连接两个表:

  • 一张桌子有电子邮件
  • 另一张表,是域黑名单。

我做了这样的事情:

SELECT
   CASE 
      WHEN b.domain IS NULL then "Invalid"
      ELSE "Valid"
   END as Validated
FROM Emails e
LEFT JOIN DomainBlacklist b
ON ENDS_WITH(LOWER(e.email), LOWER(b.domain))

但是给我一个错误:

“如果没有连接两边字段相等的条件,就不能使用左外连接。”

有人知道我该如何解决这个问题吗?

谢谢!

【问题讨论】:

    标签: sql google-bigquery


    【解决方案1】:

    以下是 BigQuery 标准 SQL

    #standardSQL
    SELECT email, 
      IF(MAX(ENDS_WITH(LOWER(email), LOWER(domain))), 'invalid', 'valid') AS Validated
    FROM `project.dataset.Emails`
    CROSS JOIN `project.dataset.DomainBlacklist`
    GROUP BY email 
    

    您可以使用以下虚拟数据测试/玩上述查询

    #standardSQL
    WITH `project.dataset.Emails` AS (
      SELECT email
      FROM UNNEST(['user1@abc.com','user2@abc.com','user3@uvw.com','user4@xyz.com']) AS email 
    ), `project.dataset.DomainBlacklist` AS (
      SELECT domain
      FROM UNNEST(['uvw.com','qwe.net']) AS domain
    )
    SELECT email, 
      IF(MAX(ENDS_WITH(LOWER(email), LOWER(domain))), 'invalid', 'valid') AS Validated
    FROM `project.dataset.Emails`
    CROSS JOIN `project.dataset.DomainBlacklist`
    GROUP BY email 
    

    结果是

    email           Validated    
    user1@abc.com   valid    
    user2@abc.com   valid    
    user3@uvw.com   invalid  
    user4@xyz.com   valid    
    

    【讨论】:

    • 嗨!您的查询在测试中效果很好,但如果我使用真实表执行,错误仍然存​​在:(。
    • 我编辑的查询是:SELECT IF ((SELECT COUNT(1) FROM Operaciones.DominioErrado d WHERE ENDS_WITH(LOWER(r.correo), LOWER(d.dominio))) > 0, 'invalid ', 'valid') AS Validated FROM Modelo.Registrados r
    • 同理:“如果没有连接两边字段相等的条件,就不能使用左外连接。” :(
    • 让我检查一下 - 我没有用实际表测试过这个,而是用表表达式(使用 WITH),所以这可能是它适用于我的示例但不适用于真实表的原因 - 会回来很快
    【解决方案2】:

    理论上应该可以将其表示为等式连接;您需要先从电子邮件地址中删除@

    SELECT
       CASE 
          WHEN b.domain IS NULL then "Invalid"
          ELSE "Valid"
       END as Validated
    FROM Emails e
    LEFT JOIN DomainBlacklist b
    ON LOWER(SPLIT(e.email, '@')[SAFE_OFFSET(1)]) = LOWER(b.domain)
    

    使用样本数据:

    WITH Emails AS (
      SELECT 'elliott@example.com' AS email UNION ALL
      SELECT 'a@b.com' UNION ALL
      SELECT 'invalid_email' UNION ALL
      SELECT 'foo@bar.com'
    ), DomainBlacklist AS (
      SELECT 'example.com' AS domain UNION ALL
      SELECT 'bar.com'
    )
    SELECT
       CASE 
          WHEN b.domain IS NULL then "Invalid"
          ELSE "Valid"
       END as Validated
    FROM Emails e
    LEFT JOIN DomainBlacklist b
    ON LOWER(SPLIT(e.email, '@')[SAFE_OFFSET(1)]) = LOWER(b.domain)
    

    【讨论】:

    • 感谢您的回答!有什么方法可以做到这一点而无需拆分?因为我们有域,而不是子域,所以如果电子邮件是“bla@something.example.com”,则脚本不起作用(或者,如果该字段不是电子邮件怎么办?)
    • 该查询仅将非电子邮件的值视为无效。您可以潜在地使用 URL 函数进行规范化;你在文档中看到NET.REG_DOMAIN 和其他人了吗? cloud.google.com/bigquery/docs/reference/standard-sql/…
    • 感谢您的链接!我会将该链接传递给我们的分析团队:)
    猜你喜欢
    • 2011-03-27
    • 1970-01-01
    • 2021-02-15
    • 2013-04-11
    • 1970-01-01
    • 2018-05-28
    • 2023-03-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多