条件加入bigquery

conditional join in bigquery

我有两张桌子。

Table 1 是一列整数。

Table 2 有三列:start_integer、end_integer、数据

简单的查询是将整数列与数据连接在一起

  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;

其中returns错误:

Error: 4.1 - 4.132: The JOIN operator's right-side table must be a small table. Switch the tables if the left-side table is smaller, or use JOIN EACH if both tables are larger than the maximum described at http://goo.gl/wXqgHs.

您是否尝试过以下查询:

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 不支持右侧表的交叉联接。

好消息(2016)! BigQuery 现在确实支持不等式连接 - 确保取消选中 "use legacy SQL option".

示例查询:

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

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

输入 table 看起来像:

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

查找 table 就像:

{
    "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 部分加入作为减少搜索的一种方式 space(我查找中的起始和终止范围 table 不倾向于跨越尽可能宽以具有不同的第 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 地址和 ip_from 和 ip_to 地址的第 1 部分和第 2 部分进行相等连接),然后通过使用 if 在组中减少它between 语句(这样做而不是 where 条件可确保您获得正确的左外连接,因此您还可以查看您处理了哪些记录但在查找 table 中没有信息)。

Defo 不是最漂亮的,可能还有一两种优化它的方法,但现在正在为我工​​作,并在 10-20 秒内查找 500K 输入 ip 地址与 16M 记录的查找 table。