2017-04-01 74 views
0

假设指示间隔I有两个表:intervals包含索引间隔(其列是i_mini_max)和values包含索引值(的列ix)。这里有一个例子:大量查询/ SQL:萨姆在由辅助表

values:  intervals: 
+---+---+ +-------+-------+ 
| i | x | | i_min | i_max | 
+-------+ +---------------+ 
| 1 | 1 | | 1 | 4 | 
| 2 | 0 | | 6 | 6 | 
| 3 | 4 | | 6 | 6 | 
| 4 | 9 | | 6 | 6 | 
| 6 | 7 | | 7 | 9 | 
| 7 | 2 | | 12 | 17 | 
| 8 | 2 | +-------+-------+ 
| 9 | 2 | 
+---+---+ 

我要总结x的值,每个间隔:

SELECT 
    i_min, 
    i_max, 
    (SELECT SUM(x) 
    FROM values 
    WHERE i BETWEEN intervals.i_min AND intervals.i_max) AS sum_x 
FROM 
    intervals 

不同之处在于:

 result: 
+-------+-------+-----+ 
| i_min | i_max | sum | 
+---------------------+ 
| 1 | 4 | 13 | // 1+0+4+9 
| 6 | 6 | 7 | 
| 6 | 6 | 7 | 
| 6 | 6 | 7 | 
| 7 | 9 | 6 | // 2+2+2 
| 12 | 17 | 0 | 
+-------+-------+-----+ 

在一些SQL引擎,这可以用做BigQuery不允许使用查询类型(“在SELECT子句中不允许使用子选择”或“如果没有条件等于来自连接两边的字段的条件,则不能使用”LEFT OUTER JOIN“”取决于synta x使用)。

必须有一种方法可以用窗口函数做到这一点,但我无法弄清楚 - 我看过的所有例子都将分区作为表的一部分。有没有不使用CROSS JOIN的选项?如果没有,做这个CROSS JOIN最有效的方法是什么?

我的数据的一些注意事项:

  • 这两个表包含许多(10⁸-10⁹)行。
  • intervals中可能有重复,而不是i
  • intervals中的两个区间要么相同,要么完全不相交(不重叠)。
  • 所有间隔的并集通常接近所有值的集合(所以它形成这个空间的一个分区)。
  • 间隔可能很大(例如,i_max-i_min <10⁶)。
+1

请编辑您的问题,并提供样本数据和预期的结果。还要说明间隔是否重叠,紧凑,稀疏。 。 。这可能会影响解决方案。 –

+0

请确保[启用标准SQL](https://cloud.google.com/bigquery/docs/reference/standard-sql/)在查询中使用这些功能。另请参阅[迁移指南](https://cloud.google.com/bigquery/docs/reference/standard-sql/migrating-from-legacy-sql)。 –

+0

@GordonLinoff好点,做完了。 – Ted

回答

3

尝试以下 - BigQuery的标准SQL

#standardSQL 
SELECT 
    i_min, i_max, SUM(x) AS sum_x 
FROM (
    SELECT i_min, i_max, ROW_NUMBER() OVER() AS line FROM `project.dataset.intervals` 
) AS intervals 
JOIN (SELECT i, x FROM `project.dataset.values` UNION ALL SELECT NULL, 0) AS values 
ON values.i BETWEEN intervals.i_min AND intervals.i_max OR values.i IS NULL 
GROUP BY i_min, i_max, line 
-- ORDER BY i_min 

,你可以玩虚拟数据/测试,如下

#standardSQL 
WITH intervals AS (
    SELECT 1 AS i_min, 4 AS i_max UNION ALL 
    SELECT 6, 6 UNION ALL 
    SELECT 6, 6 UNION ALL 
    SELECT 6, 6 UNION ALL 
    SELECT 7, 9 UNION ALL 
    SELECT 12, 17 
), 
values AS (
    SELECT 1 AS i, 1 AS x UNION ALL 
    SELECT 2, 0 UNION ALL 
    SELECT 3, 4 UNION ALL 
    SELECT 4, 9 UNION ALL 
    SELECT 6, 7 UNION ALL 
    SELECT 7, 2 UNION ALL 
    SELECT 8, 2 UNION ALL 
    SELECT 9, 2 
) 
SELECT 
    i_min, i_max, SUM(x) AS sum_x 
FROM (SELECT i_min, i_max, ROW_NUMBER() OVER() AS line FROM intervals) AS intervals 
JOIN (SELECT i, x FROM values UNION ALL SELECT NULL, 0) AS values 
ON values.i BETWEEN intervals.i_min AND intervals.i_max OR values.i IS NULL 
GROUP BY i_min, i_max, line 
-- ORDER BY i_min 
+0

再次感谢。出于好奇,是否有可能在传统SQL中做到这一点? – Ted

+0

由于传统SQL中的ON子句的限制,可以执行,但不仅仅是标准SQL的一对一转换。但可行。 –