如何解析 Snowflake 中 XML VARIANT 列中的数组?

问题描述 投票:0回答:1

我有一个带有 VARIANT 列的表,其中包含来自 Snowpipe 的 XML。我能够使用 XMLGET 和 GET 的奇怪组合来解析大多数字段的 XML。但是,有一个字段是一个数组,我只能提取标签值数组中的第一个值。每个记录在标记数组中可以有 0 - 100 个值,因此我需要足够动态的内容来涵盖所有这些场景。我花了几天时间试图解决这个问题,但我被难住了。

这里有一些命令可帮助复制我的问题以及具有部分(但不是全部)值的查询。请注意,这个查询将在 dbt 中使用,定期将数据从 XML 转换为表格,其中有数百万行进入,所以我也想在这个解析中考虑性能...我很好奇是否有人有比嵌套 XMLGET 命令更好的方法。我将在帖子底部添加所需的输出。

预先感谢任何可以帮助我的人!

create temp table if not exists temp_cf_final (RECORD_CONTENT variant);
insert into temp_cf_final
select parse_xml('<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<?opentarget version=\"1.1\"?>\n<opentarget xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n<txn id=\"20339559598\" msgIdx=\"76\" msgTot=\"86\" commitTime=\"2023-09-28T10:54:44\" userId=\"349\" oracleTxnId=\"122.17.359225\" />\n<tbl name=\"MAROON_DEV.CF_FINAL\">\n<cmd ops=\"upd\">\n<row id=\"AAIjTAAA7AAHuvTAAZ\">\n<col name=\"DATA\" type=\"varray\" />\n<varray>\n<value>1 street</value>\n<value>    </value>\n<value></value>\n<value>Nashville</value>\n<value>TN</value>\n<value>37211</value>\n<value></value>\n</varray>\n<lkup>\n<col name=\"CF_FINAL_ID\">14773</col>\n</lkup>\n</row>\n</cmd>\n</tbl>\n</opentarget>\n');
insert into temp_cf_final 
select parse_xml('<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<?opentarget version=\"1.1\"?>\n<opentarget xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n<txn id=\"20339559598\" msgIdx=\"77\" msgTot=\"86\" commitTime=\"2023-09-28T10:54:44\" userId=\"349\" oracleTxnId=\"122.17.359225\" />\n<tbl name=\"MAROON_DEV.CF_FINAL\">\n<cmd ops=\"upd\">\n<row id=\"AAIjTAAA7AAHuvTAAa\">\n<col name=\"DATA\" type=\"varray\" />\n<varray>\n<value>2486</value>\n</varray>\n<lkup>\n<col name=\"CF_FINAL_ID\">14774</col>\n</lkup>\n</row>\n</cmd>\n</tbl>\n</opentarget>\n');
select record_content
,TO_TIMESTAMP(GET(XMLGET(PARSE_XML(RECORD_CONTENT),'txn'),'@commitTime')) as last_commit_time
,GET(XMLGET(XMLGET(PARSE_XML(RECORD_CONTENT),'tbl'),'cmd'),'@ops')::string as last_operation
,CASE 
    WHEN LAST_OPERATION='ins' THEN GET(XMLGET(XMLGET(XMLGET(XMLGET(PARSE_XML(RECORD_CONTENT),'tbl'),'cmd'),'row'),'col',0),'$')
    WHEN LAST_OPERATION='upd' THEN GET(XMLGET(XMLGET(XMLGET(XMLGET(XMLGET(PARSE_XML(RECORD_CONTENT),'tbl'),'cmd'),'row'),'lkup'),'col',0),'$') 
    END::number AS CF_FINAL_ID
,SUBSTR(GET(XMLGET(PARSE_XML(RECORD_CONTENT),'tbl'),'@name'),1,CHARINDEX('.',GET(XMLGET(PARSE_XML(RECORD_CONTENT),'tbl'),'@name'))-1)::string AS CUSTOMER_SCHEMA
,GET(XMLGET(XMLGET(XMLGET(XMLGET(PARSE_XML(RECORD_CONTENT),'tbl'),'cmd'),'row'),'varray'),'$') as DATA_UPD --Works to get me either the single value of "value" or the array of values
,regexp_substr_all(GET(XMLGET(XMLGET(XMLGET(XMLGET(PARSE_XML(RECORD_CONTENT),'tbl'),'cmd'),'row'),'varray'),'$'),$$"\$":\w+$$,1,1) as DU_values --Works on the array of values, but only pulls the last in the array
,GET(XMLGET(XMLGET(XMLGET(XMLGET(XMLGET(PARSE_XML(RECORD_CONTENT),'tbl'),'cmd'),'row'),'varray'),'value'),'$')::VARCHAR as DU_first_line --Works great to get the single value, but returns only the first line of an array of values
from temp_cf_final;

从上面可以看出...

DATA_UPD 列提供了奇异值和值数组。 DU_FIRST_LINE 更进一步,生成我想要的奇异值 VARCHAR,但只给出值数组的第一行。 DU_VALUES 是我尝试通过正则表达式从数组中获取值,但经过几个小时的尝试后,这对我来说是行不通的。

我想看到的 DATA 是值 string_agg'd 和逗号分隔的数组(一旦我/我们/你弄清楚了数组解析,我就可以这样做)?

CF_FINAL_ID |数据

14773 | 1 号街,纳什维尔,田纳西州,37211, 14774 | 2486

arrays xml-parsing snowflake-cloud-data-platform
1个回答
0
投票

您可以将最后一个数组视为字符串,然后

regexp_substr_all
:

select xmlget(record_content, 'tbl') tbl
 , xmlget(tbl, 'cmd') cmd
 , xmlget(cmd, 'row') row1
 , xmlget(row1, 'varray') varray
 , regexp_substr_all(varray::string, '<value>([^<]+)', 1, 1, 'e', 1) arr
from temp_cf_final;

© www.soinside.com 2019 - 2024. All rights reserved.