引入子查询时,BigQuery为什么抱怨左联接错误?

时间:2020-05-19 19:37:52

标签: google-bigquery

问题

是否有关于为什么的解释,以下无用的错误消息显示了它的工作方式,或者是否有其他文献记载的最佳实践来利用子查询中可能丢失的数据?

问题

当我引用左联接到CTE的表中的字段时,BigQuery会产生一个令人困惑且无用的错误。

错误消息

LEFT OUTER JOIN cannot be used without a condition that is an equality of fields from both sides of the join.

特定目标

我的特殊案例是尝试通过利用针对现有dates表的子查询来计算两个日期之间的营业日。

可复制的示例

当我将子查询作为select ed字段引入时,下面的查询引发以下错误。

似乎对d2的引用导致查询中断。

with

first_dates as (
  select 1 as id, cast('2020-01-01' as date) as d
  union all
  select 2 as id, cast('2020-02-01' as date) as d
),

second_dates as (
  select 1 as id, cast('2020-01-02' as date) as d
),


timelines as (
  select 
    first_dates.id,
    first_dates.d as d1,
    second_dates.d as d2
  from
    first_dates
    -- This is the only left join in my query, and looks fine to me!
    left join second_dates using (id)
)

select 
  *,
  (
    select count(*)
    from <my_example_dates_table>
    where 
      date >= d1 
      and date < d2
      and is_business_day
      ) as n_business_days
from 
  timelines

假设

我当前的假设是BigQuery的后端将子查询转换为左联接,并在尝试这样做时遇到错误。如果是这样,我认为错误消息应该得到改善。

到目前为止的研究

我发现许多SO链接都引用了相同的问题,但是我还没有找到任何答案来解释为什么确切地出现此错误,为什么错误消息如此无用以及是否有最佳实践在BigQuery中重新创建合理的查询模式

因此,我恳请那些将其作为重复项关闭以使其保持打开状态的人,因为它专门询问有关为什么显示错误消息的答案

已经回答了许多建议,它们提出了针对特定问题的替代方法:

2 个答案:

答案 0 :(得分:1)

首先,考虑以下查询(从您的查询中简化):

with

first_dates as (
  select 1 as id, cast('2020-01-01' as date) as d
  union all
  select 2 as id, cast('2020-02-01' as date) as d
)

select 
  *,
  (
    select count(*)
    from utility.calendar -- just a simple calendar
    where 
      calendar_date = d
      ) as n_business_days
from 
  first_dates

这将执行,如果您在BQ界面中查看“执行详细信息”,则确实可以看到联接正在发生。您的假设在这里似乎是正确的。

如果将子查询更改为calendar_date >= d,则会收到LEFT OUTER JOIN cannot be used without a condition that is an equality of fields from both sides of the join错误。假设确实发生了子查询到左联接的转换,那么问题就变成了“为什么在左联接中需要相等?”

我不知道确切的原因,但是我的直觉是它与可伸缩性和查询成本估算有关。如果您的右侧表已分区,则不等式(><等)连接将无法从分区中受益,因为左侧的每一行都必须与整个右侧。

这里的解决方案是通常CROSS JOIN然后进行过滤。这会将所有比较从join子句移到where子句。

select
  id, d1, d2, count(*) as ct
from timelines
cross join <my_example_dates_table>
where date >= d1 
  and date < d2
  and is_business_day
group by 1,2,3

答案 1 :(得分:1)

除了@rtenha评论。这是Bigquery的已知问题,可以在here

中进行跟踪

此外,在这种情况下,建议将 <= > = 更改为 =

另外,以该查询为例:

选择 *, ( 选择 MIN(选择) 从 selected_t 哪里 选择> =请求)AS rounded_v FROM 小孩)

BigQuery小组建议的一种变通方法是,添加虚假的相等连接谓词,如下所示:

选择 *, ( 选择 MIN(选择) 从 selected_t 哪里 选择> =请求并选择0 *选择= 0 *请求)AS rounded_v

相关问题