BigQuery挑战:带成本拆分的客户表透视转换
问题描述
现有如下结构的BigQuery表:
| ID | TYPE | NAME | FULL COST | COST SPLIT |
|---|---|---|---|---|
| a1 | customer | john | 6 | 2 |
| a1 | customer | jack | 6 | 2 |
| a1 | customer | frank | 6 | 2 |
| a1 | environment | dev | 6 | 6 |
| a1 | sales | full | 6 | 6 |
| a2 | customer | antony | 15 | 3 |
| a2 | customer | jeff | 15 | 3 |
| a2 | customer | mark | 15 | 3 |
| a2 | customer | john | 15 | 3 |
| a2 | customer | jack | 15 | 3 |
| a2 | environment | test | 15 | 7.5 |
| a2 | environment | dev | 15 | 7.5 |
| a2 | sales | partial | 15 | 15 |
数据说明:每个ID对应唯一的FULL COST(总成本),COST SPLIT是总成本在各TYPE内的拆分值。例如ID=a1总成本为6,3个customer各拆分2,单个environment拆分6,单个sales拆分6;ID=a2遵循相同逻辑。
需要将表转换为如下结构:
| ID | customer | environment | sales | COST SPLIT |
|---|---|---|---|---|
| a1 | john | dev | full | 2 |
| a1 | jack | dev | full | 2 |
| a1 | frank | dev | full | 2 |
| a2 | antony | test | partial | 1.5 |
| a2 | jeff | test | partial | 1.5 |
| a2 | mark | test | partial | 1.5 |
| a2 | john | test | partial | 1.5 |
| a2 | jack | test | partial | 1.5 |
| a2 | antony | dev | partial | 1.5 |
| a2 | jeff | dev | partial | 1.5 |
| a2 | mark | dev | partial | 1.5 |
| a2 | john | dev | partial | 1.5 |
| a2 | jack | dev | partial | 1.5 |
转换规则:将TYPE转为列,每个ID下生成所有TYPE组合的行,新COST SPLIT需满足各TYPE对应的拆分值总和等于原表中该TYPE的COST SPLIT。请问能否通过pivot或join实现该转换?
解决方案
可以通过笛卡尔积JOIN结合聚合计算实现,这种方式比Pivot更适配生成全组合的需求(Pivot更多用于行转列的聚合场景,无法直接生成全维度组合)。
具体BigQuery SQL代码
WITH split_metrics AS ( -- 拆分各TYPE数据,同时统计每个ID下各TYPE的记录数 SELECT ID, TYPE, NAME, COST_SPLIT AS original_split, -- 统计当前ID+TYPE分组内的记录总数 COUNT(*) OVER (PARTITION BY ID, TYPE) AS type_record_count FROM `your-project.your-dataset.target-table` ), -- 提取各TYPE的独立数据集 customer_data AS ( SELECT ID, NAME AS customer, original_split, type_record_count AS cust_count FROM split_metrics WHERE TYPE = 'customer' ), env_data AS ( SELECT ID, NAME AS environment, original_split, type_record_count AS env_count FROM split_metrics WHERE TYPE = 'environment' ), sales_data AS ( SELECT ID, NAME AS sales, original_split, type_record_count AS sales_count FROM split_metrics WHERE TYPE = 'sales' ) -- 笛卡尔积关联生成全组合,计算最终拆分成本 SELECT c.ID, c.customer, e.environment, s.sales, -- 计算逻辑:单个组合的拆分成本 = 原TYPE单条拆分值 / 其他TYPE的总组合数 -- 确保各TYPE的拆分总和与原表一致 c.original_split / (e.env_count * s.sales_count) AS COST_SPLIT FROM customer_data c JOIN env_data e ON c.ID = e.ID JOIN sales_data s ON c.ID = s.ID ORDER BY c.ID, e.environment, c.customer
核心逻辑说明
- 统计维度数量:先计算每个ID下各TYPE的记录数,比如a2的customer有5条、environment有2条、sales有1条。
- 拆分独立数据集:将customer、environment、sales拆分为单独数据集,方便后续关联。
- 生成全组合:通过ID关联三个数据集,生成所有维度的笛卡尔积组合(比如a2会生成521=10条记录)。
- 计算拆分成本:每个组合的拆分成本按「原TYPE单条拆分值 ÷ 其他TYPE的总组合数」计算,确保各TYPE的拆分总和与原表完全匹配(比如a2中所有组合的拆分总和为10*1.5=15,与原customer、environment、sales的总拆分值一致)。
内容的提问来源于stack exchange,提问作者Giacomo F
相关产品推荐
相关产品推荐

