【问题标题】:conditional join in bigquerybigquery 中的条件连接
【发布时间】:2023-03-31 11:03:01
【问题描述】:

我有两张桌子。

表 1 是一列整数。

表 2 有三列:start_integer、end_integer、data

简单的查询是将整数列与数据相连接

  integer >= start_integer AND integer <= end_integer

在许多 SQL 实现中,这可以通过左条件 JOIN ... ON BETWEEN 来完成

SELECT tbl1.integer, tbl2.data FROM tbl1
LEFT JOIN tbl2 ON tbl1.integer BETWEEN tbl2.start_integer AND 
tbl2.end_integer;

但 BigQuery 似乎只支持只有一个 = 条件的 JOIN ON。

这可以通过交叉连接来完成,但 BigQuery 抱怨我的表太大。 CROSS JOIN EACH 无效。

如何在 BigQuery 的 SQL 限制下完成这个连接任务?

下面是我的 BigQuery SQL:

SELECT tbl1.integer, tbl2.data
FROM bq:data.tbl1 
CROSS JOIN bq:data.tbl2
WHERE tbl1.integer BETWEEN tbl2.start_integer AND tbl2.end_integer;

返回错误:

错误:4.1 - 4.132:JOIN 运算符的右侧表必须是小表。如果左侧表较小,则切换表,如果两个表都大于http://goo.gl/wXqgHs 中描述的最大值,则使用 JOIN EACH。

【问题讨论】:

  • 你的 between 需要移动到 WHERE,并使用 CROSS JOIN。根据文档,CROSS JOIN 操作可以返回大量数据。如果不起作用,请发布交叉查询。没有 EACH 交叉。
  • CROSS JOIN 查询和错误发布。
  • 数据的性质是什么?可能有解决此问题的好方法,具体取决于问题的性质。
  • IP 地址列表和与 IP 地址范围相关的数据。
  • 我也有这个问题。是否可以使用 UDF 将每个 ip 映射到右表中的范围?

标签: sql join google-bigquery


【解决方案1】:

好消息(2016 年)! BigQuery 现在确实支持不等式连接 - 请务必取消选中“使用旧版 SQL 选项”。

查询示例:

SELECT * 
FROM (
  SELECT 1 x
) a JOIN (
  SELECT 2 y
) b
ON a.x<b.y

使用旧版 SQL:

Error: ON clause must be AND of = comparisons of one field name from each table, ...

使用标准 SQL:

1     2

【讨论】:

  • 哦,太好了,刚刚花了一天时间试图用 R 中的数据表解决这个问题。迫不及待地想看看。
【解决方案2】:

BigQuery 不支持右侧表的交叉联接。

【讨论】:

    【解决方案3】:

    只是添加我如何解决这个问题的概述 - 有点 hacky,但我发现这是最快的方法,可以很好地扩展。

    输入表如下:

    {
        "ip": "130.211.149.140",
        "ip_int": "2194904460",
        "ip_part1": "130",
        "ip_part2": "211",
        "ip_part3": "149",
        "ip_part4": "140",
        "num_requests": "6811"
      }
    

    查找表是这样的:

    {
        "de_ip_key": "DE18_92.66.156.93_92.66.156.112",
        "ip_key": "92.66.156.93_92.66.156.112",
        "ip_from_int": "1547869277",
        "ip_to_int": "1547869296",
        "ip_from": "92.66.156.93",
        "ip_to": "92.66.156.112",
        "naics_code": "518210",
        "ip_from_part1": "92",
        "ip_from_part2": "66",
        "ip_from_part3": "156",
        "ip_from_part4": "93",
        "ip_to_part1": "92",
        "ip_to_part2": "66",
        "ip_to_part3": "156",
        "ip_to_part4": "112"
      }
    

    因此,使用 ip 地址的第 1 部分和第 2 部分来加入作为减少搜索空间的一种方式(我的查找表中的 from 和 to 范围往往不会像第 1 部分和第 2 部分一样宽- 如果是这样,这种方法失败了)。

    select
      ip,
      ip_int,
      -- pick first info from de
      first(ip_key) as ip_key,
      first(de_ip_key) as de_ip_key,
      first(naics_code) as naics_code
    from
      (
      select 
        ip as ip,
        ip_int as ip_int,
        ip_key as ip_key,
        de_ip_key as de_ip_key,
        naics_code as naics_code,
      from 
        -- join based on part 1 and 2 of ip from range
        (
        select 
          input.ip as ip,
          input.ip_int as ip_int,
          if(input.ip_int between de.ip_from_int and de.ip_to_int,de.ip_key,null) as ip_key,
          if(input.ip_int between de.ip_from_int and de.ip_to_int,de.de_ip_key,null) as de_ip_key,
          if(input.ip_int between de.ip_from_int and de.ip_to_int,de.naics_code,null) as naics_code,
        from
          [ip.lookup_input_tbl]  input
        left outer join each 
          [digital_element.data_naics_code] de
        on
          input.ip_part1=de.ip_from_part1
          and
          input.ip_part2=de.ip_from_part2
        group by 1,2,3,4,5
        ),
        -- join based on part 1 and 2 of ip to range
        (
        select 
          input.ip as ip,
          input.ip_int as ip_int,
          if(input.ip_int between de.ip_from_int and de.ip_to_int,de.ip_key,null) as ip_key,
          if(input.ip_int between de.ip_from_int and de.ip_to_int,de.de_ip_key,null) as de_ip_key,
          if(input.ip_int between de.ip_from_int and de.ip_to_int,de.naics_code,null) as naics_code,
        from
          [ip.lookup_input_tbl]  input
        left outer join each 
          [digital_element.data_naics_code] de
        on
          input.ip_part1=de.ip_to_part1
          and
          input.ip_part2=de.ip_to_part2
        group by 1,2,3,4,5
        ),
      group by 1,2,3,4,5
      -- order so null records from either join go to bottom and get left behind on the first group by
      order by ip_int,ip_key desc
      )
    group by 1,2
    

    所以它基本上会吹出数据(通过在 ip 地址的第 1 部分和第 2 部分以及 ip_from 和 ip_to 地址上进行相等连接),然后使用 if between 语句在组上减少它(这样做而不是 where 条件确保您获得正确的左外连接,因此您还可以查看您处理了哪些记录但在查找表中没有信息)。

    Defo 不是最漂亮的,可能还有一两种优化它的方法,但现在对我有用,并在 10-20 秒内根据 16M 记录的查找表查找 500K 输入 IP 地址。

    【讨论】:

      【解决方案4】:

      您是否尝试过以下查询:

      SELECT tbl1.integer, tbl2.data
      FROM bq:data.tbl1 
      JOIN EACH bq:data.tbl2
      ON tbl1.integer >= tbl2.start_integer AND tbl1.integer <= tbl2.end_integer;
      

      【讨论】:

      • BigQuery 不支持 JOIN 上的不等式。
      • 2016 年更新:新的 BigQuery SQL 确实支持 JOIN 上的不等式 - 取消选中“旧版 SQL”。 :)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-10
      • 2018-05-20
      • 2017-11-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多