【问题标题】:BigQuery - Left Join two tables ON a column OR anotherBigQuery - 在列或另一个列上左连接两个表
【发布时间】:2021-09-25 03:56:39
【问题描述】:

我想在两个表上执行左连接。我将加入的字段是电子邮件地址。由于左侧的表 I 有两个可能不同的电子邮件字段,我希望如果第一封电子邮件的加入失败并返回空值,则在另一个电子邮件字段上执行第二次加入。最后,我想丢弃那些没有与两个连接中的任何一个匹配的条目。

我想过做这样的事情:

SELECT *
FROM a
LEFT JOIN b
ON
    a.address1 = b.email
    OR a.address2 = b.email

但是,这会返回一条错误消息,指出 LEFT OUTER JOIN cannot be used without a condition that is an equality of fields from both sides of the join。

实现这一目标的正确方法是什么?

【问题讨论】:

  • 样本数据和期望的结果真的很有帮助。

标签: mysql sql google-bigquery left-join


【解决方案1】:

您也许可以使用联合来表达您的逻辑:

SELECT * FROM a LEFT JOIN b ON a.address1 = b.email
UNION
SELECT * FROM a LEFT JOIN b ON a.address2 = b.email;

【讨论】:

  • 在 b 上同时匹配 a.address1 和 a.address2 的条目会发生什么情况?他们会出现重复
  • 我不是大查询专家,但在sql标准中,如果将UNION ALL替换为UNION,则只会返回不同的值
  • 是的,但是想象一下a.address1 和a.address2 是不同的,它们都出现在我的桌子上b。然后,它们将被连接并具有与表b 不同的值,因此被视为不同的条目,在那里有重复。我需要,如果第一个连接与表b 匹配,则不执行第二个连接。
【解决方案2】:

OR 在JOIN 条件下确实很难优化查询。因此,BigQuery 使OR 的使用变得困难。

我认为您可以通过以下方式改写查询:

SELECT *
FROM a CROSS JOIN
     UNNEST(ARRAY[address1, address2]) address LEFT JOIN
     b
     ON address = b.email;

【讨论】:

    【解决方案3】:

    考虑以下 (BigQuery) 方法

    SELECT * EXCEPT(row_key, priority)
    FROM (
      SELECT *, TO_JSON_STRING(a) row_key, IF(b.email IS NULL, 3, 1) priority
      FROM `project.dataset.tableA` a LEFT JOIN `project.dataset.tableB` b
      ON a.address1 = b.email
      UNION ALL
      SELECT *, TO_JSON_STRING(a), IF(b.email IS NULL, 3, 2) 
      FROM `project.dataset.tableA` a LEFT JOIN `project.dataset.tableB` b 
      ON a.address2 = b.email
    )
    WHERE true 
    QUALIFY ROW_NUMBER() OVER(PARTITION BY row_key ORDER BY priority NULLS LAST) = 1     
    

    或者您可以使用不那么冗长/更通用(这样您可以避免冗余代码片段,如果您需要两个以上条件,这可能很有用)版本

    SELECT * EXCEPT(row_key, priority)
    FROM (
      SELECT a.*, b.*, TO_JSON_STRING(a) row_key, IF(b.email IS NULL, 3, c.priority) priority
      FROM `project.dataset.tableA` a, 
      UNNEST([STRUCT(address1 as address, 1 as priority), (address2, 2)]) c
      LEFT JOIN `project.dataset.tableB` b
      ON c.address = b.email
    )
    WHERE TRUE 
    QUALIFY ROW_NUMBER() OVER(PARTITION BY row_key ORDER BY priority NULLS LAST) = 1
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-19
      • 1970-01-01
      • 2022-08-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多