条件加入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。
我有两张桌子。
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。