从snowflake中的xml数据中检索标记(子节点)内的值的sql查询

5gfr0r5j  于 2021-08-13  发布在  Java
关注(0)|答案(2)|浏览(377)

我有一个包含以下数据的xml(已编辑)文件:

<dept dept_id="1" dept_name="Marketing">
     <progress>1</progress>
    <employee empname="a">
         <end> 1 </end>
        <address addr1="123 abc">
        ...
        </address>
    </employee>
</dept>
<dept dept_id="2" dept_name="Sales">
    <progress>1</progress>
    <employee empname="b">
        <end> 1 </end>
        <address addr1="456 cde">
        ...
        </address>
    </employee>
</dept>

我将这个文件放在awss3中,然后使用“copy into”将数据传输到variant列中snowflake中的一个外部表中。如下所示:

copy into DB.AWS_S3_STAGE_SCHEMA.test_XML_copy
  from @AWS_S3_LANDING/websiteXML/Test_xml.xml
  FILE_FORMAT = ( TYPE =  XML STRIP_OUTER_ELEMENT = TRUE  )  ;

现在,我可以从这个表中查询数据,并使用以下查询检索标签中的“marketing”和“sales”之类的数据(我从snowflake docs获得语法并使用它):

SELECT
    GET(xmldata, '@dept_id')::integer as dept_id,
    GET(xmldata, '@dept_name')::string as dept_name
FROM test_XML_copy;

但是,我无法查询子节点中标记内的数据。例如:我需要像“a”和“123 ”这样的数据。如果有人能在这个问题上帮助我,我将不胜感激。

suzh9iv8

suzh9iv81#

结合使用 XMLGET 以及 GET 函数来遍历xml文档中的嵌套对象。
前者帮助获取当前标记下的整个标记对象,而后者允许查询当前标记中的属性和常规值。

SELECT
    -- <dept> (root)
    GET(xmldata, '@dept_id')::integer as dept_id,
    GET(xmldata, '@dept_name')::string as dept_name,
    -- <dept>.<employee>
    GET(XMLGET(xmldata, 'employee'), '@empname')::string as employee_name,
    -- <dept>.<employee>.<address>
    GET(XMLGET(XMLGET(xmldata, 'employee'), 'address'), '@addr1')::string as address_1
FROM test_XML_copy;

这将产生:

+---------+-----------+---------------+-----------+                             
| DEPT_ID | DEPT_NAME | EMPLOYEE_NAME | ADDRESS_1 |
|---------+-----------+---------------+-----------|
|       1 | Marketing | a             | 123 abc   |
|       2 | Sales     | b             | 456 def   |
| ...     | ...       | ...           | ...       |
+---------+-----------+---------------+-----------+

您的示例数据显示子标记没有重复,但是如果它们确实重复(例如多个) employee 在每个 dept )那么 FLATTEN 可以先用来生产一个 employee 每行和上述方法可以重新应用。或者,如果它是标记结构的固定形式,并且它们总是有序的,那么您可以在中使用示例号 XMLGET 指向每个对象(隐式默认值为0,第一个对象)。
将文档分解为每个员工和每个地址一行的示例内部标记:

SELECT
xmldata:"@dept_id"::integer as dept_id,
xmldata:"@dept_name"::string as dept_name,
emp.value:"@empname"::string as employee_name,
addr.value:"@addr1"::string as address_1
FROM
test_XML_copy,
LATERAL FLATTEN(xmldata:"$") emp,
LATERAL FLATTEN(emp.value:"$") addr
WHERE emp.value:"@" = 'employee' AND addr.value:"@" = 'address';

(这将产生与上述类似的结果,例如op问题中提供的示例)
注意:还可以将路径语法用于 $ 以及 @ 用于导航结构而不是嵌套函数的字符,但这些字符依赖于输入数据结构的严格顺序:

-- See outer / inner structures in 'JSON' form
SELECT
    xmldata:"@" dept_tag,
    xmldata:"$" dept_tag_contents
FROM test_XML_copy;

-- Sample equivalent query using path expressions, relying on ordering:
SELECT
    xmldata:"@dept_id",
    xmldata:"@dept_name",
    xmldata:"$"[1]."@empname",
    xmldata:"$"[1]."$"[1]."@addr1"
FROM test_XML_copy;
zfciruhq

zfciruhq2#

要从子节点提取数据,需要使用横向展平来转换数据,例如展平 <employee> 元素并获取 emp_name 属性:

select
       XMLGET( xmldata, '@dept_id' ):"$"::string AS dept_id
     , XMLGET( xmldata, '@dept_name' ):"$"::string AS dept_name
     , XMLGET( emp.value, '@empname' ):"$"::string as empname
from
    test_XML_copy
    ,  lateral FLATTEN(test_XML_copy.xmldata:"$") emp
  where emp.value like '<employee>%'
  order by dept_id, empname;

本文提供了一些有关在snowflake中查询xml的非常有用的信息:https://community.snowflake.com/s/article/querying-nested-xml-in-snowflake

相关问题