繁体   English   中英

BigQuery 重现在子选择中使用另一个表的查询

[英]BigQuery reproducing a query that use another table in a subselect

我无法在 BigQuery 中重现类似于以下 MSSQL 查询的查询:

SELECT 
  COL1,
  COL2, COL3,
  CASE
    WHEN ( COL1 % 2 ) = 0 THEN COL2
    ELSE (SELECT TOP 1 COL99 FROM ANOTHER_TABLE AS AT WHERE AT.COL8 = T.COL2 AND AT.COL9 < T.COL3 ORDER BY AT.COL9 DESC)
  END AS COL4

FROM TABLE AS T

首先,我尝试重现 BQ 上的查询,如下所示:

SELECT 
  COL1,
  COL2, COL3,
  CASE
    WHEN ( COL1 % 2 ) = 0 THEN COL2
    ELSE (SELECT COL99 FROM PROJECT.DATASET.ANOTHER_TABLE AS AT WHERE AT.COL8 = T.COL2 AND AT.COL9 < T.COL3 ORDER BY AT.COL9 DESC LIMIT 1)
  END AS COL4

FROM PROJECT.DATASET.TABLE AS T

但它会导致错误: Correlated subqueries that reference other tables are not supported unless they can be de-correlated, such as by transforming them into an efficient JOIN.

我可以理解这个错误,我同意原始查询不是很优化,因为可以对表中的每一行执行子查询。

知道我尝试了以下不会导致错误但给出错误(太多)结果的方法:

SELECT 
  COL1,
  COL2, COL3,
  CASE
    WHEN ( COL1 % 2 ) = 0 THEN COL2
    ELSE AT.COL99
  END AS COL4

FROM PROJECT.DATASET.TABLE AS T
LEFT JOIN (
  SELECT * FROM (
    SELECT 
       COL99,
       COL8,
       COL9
       ROW_NUMBER() OVER (PARITION BY COL8 ORDER BY COL9 DESC) AS rn
  ) AS TMP
  /*WHERE TMP.rn = 1*/
) AS AT
ON AT.COL8 = T.COL2
AND AT.COL9 < T.COL3

此查询返回的行比预期的多,知道条件“AND AT.COL9 < T.COL3”是正常的,但我很难找出如何采用最小 ROW_NUMBER 值 (rn) 来重现原始查询的 TOP 1 .

我试图将TMP.rn = 1放入 AT 表中,但问题是它并不总是第一个符合条件AND AT.COL9 < T.COL3的值。

要恢复,我的目标是能够在 BigQuery 上重现此问题顶部的第一个查询,我已经尝试了一些但我正在阻止如何获取与条件AND AT.COL9 < T.COL3匹配的 ROW_NUMBER (rn) 的最小值AND AT.COL9 < T.COL3 .

有没有人有过类似的用例?

编辑:添加输入和 output:

  • 表为 T:
列1 列2 列3
1234 AAA级 25/12/2022
1235 BBB 25/12/2022
1236 CCC 认证 25/12/2022
1337 AAA级 24/12/2022
1238 AAA级 23/12/2022
1239 AAA级 22/12/2022
  • 另一个表
COL99 COL8 COL9
1111 AAA级 25/12/2022
2222 BBB 25/12/2022
3333 CCC 认证 25/12/2022
9999 AAA级 23/12/2022
8888 AAA级 22/12/2022
7777 AAA级 21/12/2022
  • 预计 output
列1 列2 列3 列4
1234 AAA级 25/12/2022 AAA级
1235 BBB 25/12/2022 NULL
1236 CCC 认证 25/12/2022 CCC 认证
1237 AAA级 24/12/2022 9999
1238 AAA级 23/12/2022 AAA级
1239 AAA级 22/12/2022 7777

您可以使用FIRST_VALUE() window function:

SELECT DISTINCT T.COL1, T.COL2, T.COL3,
       CASE
         WHEN T.COL1 % 2 = 0 THEN T.COL2
         ELSE FIRST_VALUE(AT.COL99) OVER (PARTITION BY T.COL1, T.COL2, T.COL3 ORDER BY AT.COL9 DESC)
       END AS COL4
FROM FIRST_TABLE AS T LEFT JOIN ANOTHER_TABLE AS AT
ON AT.COL8 = T.COL2 AND AT.COL9 < T.COL3 AND T.COL1 % 2 <> 0;

如果COL1在第一个表中是唯一的,您可以将PARTITION BY子句简化为:

OVER (PARTITION BY T.COL1 ORDER BY AT.COL9 DESC)

请参阅演示(对于 MySql,但它是标准 SQL)。

@forpas 提供的查询在我的示例中返回了良好的结果,但没有返回我在实际用例中等待的结果。

但是@forpas 的想法启发了我,我找到了解决问题的方法。

它在@forpas 提供的链接中给出了相同的结果,查询在 MySQL 中如下所示:

SELECT T.COL1, T.COL2, T.COL3,
       CASE
         WHEN T.COL1 % 2 = 0 THEN T.COL2
         ELSE AT1.COL99
       END AS COL4
FROM FIRST_TABLE AS T 
LEFT JOIN (
  SELECT * FROM (
    SELECT 
      AT.COL99, 
      T.COL2, 
      T.COL3, 
      ROW_NUMBER() OVER (PARTITION BY T.COL3, T.COL2, AT.COL8 ORDER BY AT.COL9 DESC) AS COUNTER 
    FROM ANOTHER_TABLE AS AT
    INNER JOIN FIRST_TABLE AS T
    ON AT.COL8 = T.COL2 AND AT.COL9 < T.COL3) TEMP
  WHERE TEMP.COUNTER = 1
) AS AT1
ON AT1.COL2 = T.COL2 AND AT1.COL3 = T.COL3 ;

查询可能很复杂,如果有人有更优化的东西,我会很乐意尝试。

谢谢@forpas 的提议!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM