使用范围简化数组查询

Posted

技术标签:

【中文标题】使用范围简化数组查询【英文标题】:Simplify Array Query with Range 【发布时间】:2018-02-26 10:43:06 【问题描述】:

我有一个大查询数据表,其中包含 512 个变量作为数组,名称很长(x__x_arrVal_arrSlices_0__arrValues 到 arrSlices_511)。每个数组中有 360 个值。双工具无法计算这种形式的数组。这就是我想将每个值作为输出的原因。

我现在使用的查询摘录是:

SELECT
 timestamp, x_stArrayTag_sArrayName, x_stArrayTag_sComission,
 1 as row,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(1)] AS f001,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(10)] AS f010,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(20)] AS f020,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(30)] AS f030,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(40)] AS f040,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(50)] AS f050,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(60)] AS f060,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(70)] AS f070,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(80)] AS f080,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(90)] AS f090,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(100)] AS f100,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(110)] AS f110,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(120)] AS f120,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(130)] AS f130,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(140)] AS f140,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(150)] AS f150,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(160)] AS f160,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(170)] AS f170,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(180)] AS f180,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(190)] AS f190,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(200)] AS f200,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(210)] AS f210,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(220)] AS f220,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(230)] AS f230,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(240)] AS f240,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(250)] AS f250,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(260)] AS f260,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(270)] AS f270,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(280)] AS f280,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(290)] as f290,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(300)] AS f300,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(310)] AS f310,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(320)] AS f320,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(330)] AS f330,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(340)] AS f340,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(350)] AS f350,
 x__x_arrVal_arrSlices_1__arrValues[OFFSET(359)] AS f359

 FROM
 `project.table` 

 WHERE
 _PARTITIONTIME >= "2017-01-01 00:00:00"
 AND _PARTITIONTIME < "2018-02-16 00:00:00"

UNION ALL

不幸的是,我得到的输出只是所有值的断裂。使用此查询获取所有 512*360 值是不可能的,因为如果我对所有切片使用此查询,我将达到 bigquery 的限制。

是否可以重命名长名称并选择范围?

最好的问候 斯科蒂

【问题讨论】:

虽然可以更改您的查询以适应 256KB 的查询长度限制,但您最终将拥有 ~180000 列,这超过了 BigQuery 10000 列的限制。这真的是您需要的输出,还是您更喜欢 360 行和 512 列? ~180000 列相当多。我需要最适合分析的输出。 360 行和 512 列应该就可以了。 取决于您对数据的实际操作 - 它可以是 360 行和 512 列或 512 行和 360 列(后者听起来更适合我目前听到的内容) -但仍然 - 你能分享你用你使用的任何 BI 工具做了什么样的魔法。可能所有这些魔法都可以在 BigQuery 中完成,因此根本不需要重组您的表 - 只是猜测:o) 【参考方案1】:

您可以使用 UNNEST 获得 360 行和 512 列。这是一个小例子:

WITH data AS (
  SELECT
    [1, 2, 3, 4] as a,
    [2, 3, 4, 5] as b,
    [3, 4, 5, 6] as c
)
SELECT v1, b[OFFSET(off)] as v2, c[OFFSET(off)] as v3
FROM data, unnest(a) as v1 WITH OFFSET off

输出:

v1  v2  v3   
1   2   3    
2   3   4    
3   4   5    
4   5   6   

【讨论】:

【参考方案2】:

考虑到您正在处理的表格有点凌乱 - 在做出重组决策时,重要的方面是查询的实用性以实现该决策

在您的特定情况下 - 我建议完全展平数据,如下所示(每行将转换为 ~180000 行,每行代表原始行中数组之一的元素之一 - 切片字段将表示数组编号和pos 将表示该数组中的元素位置) - 查询足够通用,可以处理任何数量/名称的切片和数组大小,同时结果灵活且通用,足以用于任何可以想象的算法中

#standardSQL
SELECT 
  id, 
  slice,
  pos,
  value
FROM `project.dataset.messytable` t,
UNNEST(REGEXP_EXTRACT_ALL(TO_JSON_STRING(t), r'"x__x_arrVal_arrSlices_(\d+)":\[.*?\]')) slice WITH OFFSET x
JOIN UNNEST(REGEXP_EXTRACT_ALL(TO_JSON_STRING(t), r'"x__x_arrVal_arrSlices_\d+":\[(.*?)\]')) arr WITH OFFSET y
ON x = y,
UNNEST(SPLIT(arr)) value WITH OFFSET pos   

您可以使用下面的虚拟示例测试/玩它

#standardSQL
WITH `project.dataset.messytable` AS (
  SELECT 1 id, 
    [ 1,  2,  3,  4,  5] x__x_arrVal_arrSlices_0, 
    [11, 12, 13, 14, 15] x__x_arrVal_arrSlices_1,
    [21, 22, 23, 24, 25] x__x_arrVal_arrSlices_2 UNION ALL
  SELECT 2 id, 
    [ 6,  7,  8,  9, 10] x__x_arrVal_arrSlices_0, 
    [16, 17, 18, 19, 20] x__x_arrVal_arrSlices_1,
    [26, 27, 28, 29, 30] x__x_arrVal_arrSlices_2 
)
SELECT 
  id, 
  slice,
  pos,
  value
FROM `project.dataset.messytable` t,
UNNEST(REGEXP_EXTRACT_ALL(TO_JSON_STRING(t), r'"x__x_arrVal_arrSlices_(\d+)":\[.*?\]')) slice WITH OFFSET x
JOIN UNNEST(REGEXP_EXTRACT_ALL(TO_JSON_STRING(t), r'"x__x_arrVal_arrSlices_\d+":\[(.*?)\]')) arr WITH OFFSET y
ON x = y,
UNNEST(SPLIT(arr)) value WITH OFFSET pos  

结果如下

Row id  slice   pos value    
1   1   0       0     1  
2   1   0       1     2  
3   1   0       2     3  
4   1   0       3     4  
5   1   0       4     5  
6   1   1       0     11     
7   1   1       1     12     
8   1   1       2     13     
9   1   1       3     14     
10  1   1       4     15     
11  1   2       0     21     
12  1   2       1     22     
13  1   2       2     23     
14  1   2       3     24     
15  1   2       4     25     
16  2   0       0     6  
17  2   0       1     7  
18  2   0       2     8  
19  2   0       3     9  
20  2   0       4     10     
21  2   1       0     16     
22  2   1       1     17     
23  2   1       2     18     
24  2   1       3     19     
25  2   1       4     20     
26  2   2       0     26     
27  2   2       1     27     
28  2   2       2     28     
29  2   2       3     29     
30  2   2       4     30      

【讨论】:

以上是关于使用范围简化数组查询的主要内容,如果未能解决你的问题,请参考以下文章

C++基于范围的for循环详解

Mongoose - 使用 find() 查询文档,其中嵌套数组值的总和在一定范围内

MySQL EntityManager 范围查询

如何从给定数组的范围查询中获取给定值的最小异或值

带有排序的 MongoDB 范围查询 - 如何加快速度?

MySQL 查询性能与日期范围和时间步长