bigquery中的条件连接

时间:2015-07-30 08:28:07

标签: sql join google-bigquery

我有两张桌子。

表1是一个整数的COLUMN。

表2有三个COLUMNS: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。

4 个答案:

答案 0 :(得分:5)

好消息(2016)! BigQuery现在支持不等式连接 - 确保取消选中&#34;使用旧SQL选项&#34;。

示例查询:

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

enter image description here

答案 1 :(得分:2)

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

答案 2 :(得分:0)

只是添加我如何做这个问题的大纲 - 有点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秒内查找500K输入IP地址对16M记录的查找表。

答案 3 :(得分:-1)

您是否尝试过以下查询:

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;