繁体   English   中英

如何使用 jupyter notebook 或 SQL 对多个列进行反透视?

[英]How can I unpivot multiple columns using jupyter notebook or SQL?

我在父子关系中有一个表结构,我需要对具有不同值的多个列进行逆透视。

下面是一个例子:

在此处输入图片说明

我放在这个表中的小例子。

注意:我在这里只放了几列,但我有 215 列以这种方式使用不同的 ID 和名称。 所以我的目标是在预期结果表中展平所有与 p_id 和/或 c_id 相关的列。

我正在使用雪花做这个练习。 但我也熟悉 jupyter notebook。 随意提供 SQL 中的解决方案或使用 Python jupyter notebook。 您还可以建议任何其他方法来处理此类数据。

此图片是评论部分的一部分。 请检查突出显示的部分。 在此处输入图片说明

让我们首先创建一个形状类似于描述中的表格:

CREATE OR REPLACE TABLE weird_table
AS 
SELECT 1 AS a, 'b' b, 1 pip1, 2 pip2, 3 pip3, 4 pip4, 11 rip1, 12 rip2, 13 rip3, 14 rip4
UNION ALL SELECT 2 , 'c', 124, 3123, 123, 123, 1231 ,9, 99,999
;

[![enter image description here][1]][1]

现在我们可以使用 JavaScript 在 Snowflake 中创建一个存储过程。 此处脚本获取表的名称。 然后它获取所有以数字结尾的列并使用这些列生成不同的SELECT语句,并将它们与UNION ALL合并:

CREATE OR REPLACE PROCEDURE custom_unpivot(TABLE_NAME VARCHAR)
RETURNS STRING
LANGUAGE JAVASCRIPT
AS
$$
var stmt = snowflake.createStatement({
    sqlText: "SELECT * FROM " + TABLE_NAME + " LIMIT 1;",    
});
stmt.execute();

var cols=[];
for (i = 1; i <= stmt.getColumnCount(); i++) {
  cols.push(stmt.getColumnName(i));
}
var idCols = cols.filter(x => !x.match(/[0-9]+$/));
var unpivotCols = cols.filter(x => x.match(/[0-9]+$/));
var maxUnpivot = Math.max(...unpivotCols.map(x => parseInt(x.match(/[0-9]+$/))));
var colsSansSuffix = [...new Set(unpivotCols.map(x => x.replace(/[0-9]+$/, '')))];

selectsToUnion = [];
for (i = 1; i <= maxUnpivot; i++) {
  selectsToUnion.push(
    "SELECT "+idCols+","+colsSansSuffix.map(x=>" "+x+i+" AS "+x)+" FROM "+TABLE_NAME
  );
}
return selectsToUnion.join('\nUNION ALL\n');
$$
;

当您调用该过程时,它会返回一个组合的SELECT语句,该语句为您提供所需的“unpivot”:

CALL custom_unpivot('weird_table');

SELECT A,B, PIP1 AS PIP, RIP1 AS RIP FROM weird_table
UNION ALL
SELECT A,B, PIP2 AS PIP, RIP2 AS RIP FROM weird_table
UNION ALL
SELECT A,B, PIP3 AS PIP, RIP3 AS RIP FROM weird_table
UNION ALL
SELECT A,B, PIP4 AS PIP, RIP4 AS RIP FROM weird_table

如果您运行生成的 SQL,它会产生所需的结果:

在此处输入图片说明

一旦您了解此模式在存储过程中的工作方式,那么可能性是无穷无尽的。


对于评论中的后续操作,请尝试将结果查询嵌入到这样的过滤器中:

SELECT *
FROM (
  SELECT A,B, PIP1 AS PIP, RIP1 AS RIP FROM A_weird_table
  UNION ALL
  SELECT A,B, PIP2 AS PIP, RIP2 AS RIP FROM A_weird_table
  UNION ALL
  SELECT A,B, PIP3 AS PIP, RIP3 AS RIP FROM A_weird_table
  UNION ALL
  SELECT A,B, PIP4 AS PIP, RIP4 AS RIP FROM A_weird_table
  UNION ALL
  SELECT A,B, PIP5 AS PIP, RIP5 AS RIP FROM A_weird_table
)
WHERE pip>0 AND rip>0;

暂无
暂无

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

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