我们说我有一个文档,其中包含相应的XML元数据文件,如下所示。此XML文件包含与文档有关的索引字段:
<Document>
<Indices>
<IndexField>
<indexName>DOCID</indexName>
<indexValue>49626502</indexValue>
</IndexField>
<IndexField>
<indexName>EMPLOYEEID</indexName>
<indexValue>248572405</indexValue>
</IndexField>
<IndexField>
<indexName>LASTNAME</indexName>
<indexValue>BROWN</indexValue>
</IndexField>
<IndexField>
<indexName>FIRSTNAME</indexName>
<indexValue>RALPH</indexValue>
</IndexField>
<IndexField>
<indexName>CITY</indexName>
<indexValue>PORTLAND</indexValue>
</IndexField>
<IndexField>
<indexName>STATE</indexName>
<indexValue>OR</indexValue>
</IndexField>
</Indices>
</Document>
我已将XML文件加载到SQL表中,然后我将提取属性值并将其加载到另一个表中。我有成千上万的这些文件。生成元数据文件的方式,如果源系统没有填充字段,让我们说CITY或STATE,则不会在文件中创建XML标记。我遇到的挑战是元数据文件缺乏一致性或一致性,因为一个索引值可能比另一个索引值更多(基于源系统中填充的内容与空白)。
以下是我如何提取要加载到不同表中的属性:
SELECT
DOCID = CASE WHEN XMLDATA.exist('/Document/Indices/IndexField[indexName="DOCID"]') = 1 then XMLData.value('(//*[local-name()="indexValue"])[1]','varchar(max)') else NULL end,
EMPLOYEEID = CASE WHEN XMLDATA.exist('/Document/Indices/IndexField[indexName="EMPLOYEEID"]') = 1 then XMLData.value('(//*[local-name()="indexValue"])[2]','varchar(max)') else NULL end,
LASTNAME = CASE WHEN XMLDATA.exist('/Document/Indices/IndexField[indexName="LASTNAME"]') = 1 then XMLData.value('(//*[local-name()="indexValue"])[3]','varchar(max)') else NULL end,
FIRSTNAME = CASE WHEN XMLDATA.exist('/Document/Indices/IndexField[indexName="FIRSTNAME"]') = 1 then XMLData.value('(//*[local-name()="indexValue"])[4]','varchar(max)') else NULL end
对于每个字段,我首先运行它以确保它存在于XML文件中:
XMLDATA.exist(&#39; / Document / Indices / IndexField [indexName =&#34; DOCID&#34;]&#39;)= 1
然后,我为indexValue提取位置值:
XMLData.value(&#39;(// * [本地名称()=&#34; indexValue&#34])[1]&#39;,&#39; VARCHAR(最大)&#39;)
我遇到的问题是如果文件中缺少XML标记,它会抛出后续字段的位置indexValue。
我的问题是 - 基于提供的XML格式,我如何推断给定indexName的indexValue?
答案 0 :(得分:0)
找到需要IndexField
值的indexName
并提取其indexValue
declare @x xml = '<Document>
<Indices>
<IndexField>
<indexName>DOCID</indexName>
<indexValue>49626502</indexValue>
</IndexField>
<IndexField>
<indexName>EMPLOYEEID</indexName>
<indexValue>248572405</indexValue>
</IndexField>
<IndexField>
<indexName>LASTNAME</indexName>
<indexValue>BROWN</indexValue>
</IndexField>
<IndexField>
<indexName>FIRSTNAME</indexName>
<indexValue>RALPH</indexValue>
</IndexField>
<IndexField>
<indexName>CITY</indexName>
<indexValue>PORTLAND</indexValue>
</IndexField>
<IndexField>
<indexName>STATE</indexName>
<indexValue>OR</indexValue>
</IndexField>
</Indices>
</Document>';
select DOCID=@x.value('(//IndexField[indexName[1]="DOCID"]/indexValue)[1]','varchar(max)')
, NOFIELD=@x.value('(//IndexField[indexName[1]="NOFIELD"]/indexValue)[1]','varchar(max)')
--, ..
答案 1 :(得分:0)
我的建议:与GROUP BY
和MAX()
一起使用 old-fashionded-pivot 。缺少的值只会显示为NULL
。
CTE DervivedTable
将首先使用行方式数据创建普通表。剩下的就是pivot
:
DECLARE @tbl TABLE(ID INT,XmlData XML);
INSERT INTO @tbl VALUES
(1,'<Document>
<Indices>
<IndexField>
<indexName>DOCID</indexName>
<indexValue>49626502</indexValue>
</IndexField>
<IndexField>
<indexName>EMPLOYEEID</indexName>
<indexValue>248572405</indexValue>
</IndexField>
<IndexField>
<indexName>LASTNAME</indexName>
<indexValue>BROWN</indexValue>
</IndexField>
<IndexField>
<indexName>FIRSTNAME</indexName>
<indexValue>RALPH</indexValue>
</IndexField>
<IndexField>
<indexName>CITY</indexName>
<indexValue>PORTLAND</indexValue>
</IndexField>
<IndexField>
<indexName>STATE</indexName>
<indexValue>OR</indexValue>
</IndexField>
</Indices>
</Document>')
,(2,'<Document>
<Indices>
<IndexField>
<indexName>DOCID</indexName>
<indexValue>2222 id</indexValue>
</IndexField>
<IndexField>
<indexName>EMPLOYEEID</indexName>
<indexValue>2222 emp</indexValue>
</IndexField>
<IndexField>
<indexName>LASTNAME</indexName>
<indexValue>222 last</indexValue>
</IndexField>
<IndexField>
<indexName>FIRSTNAME</indexName>
<indexValue>222 first</indexValue>
</IndexField>
<IndexField>
<indexName>CITY</indexName>
<indexValue>222 city</indexValue>
</IndexField>
<IndexField>
<indexName>STATE</indexName>
<indexValue>222 state</indexValue>
</IndexField>
</Indices>
</Document>');
- 查询
WITH DerivedTable AS
(
SELECT ID
,f.value('indexName[1]','nvarchar(max)') AS indexName
,f.value('indexValue[1]','nvarchar(max)') AS indexValue
FROM @tbl AS tbl
CROSS APPLY tbl.XmlData.nodes('/Document/Indices/IndexField') AS A(f)
)
SELECT ID
,MAX(CASE WHEN indexName='DOCID' THEN indexValue END) AS DOCID
,MAX(CASE WHEN indexName='EMPLOYEEID' THEN indexValue END) AS EMPLOYEEID
,MAX(CASE WHEN indexName='LASTNAME' THEN indexValue END) AS LASTNAME
,MAX(CASE WHEN indexName='FIRSTNAME' THEN indexValue END) AS FIRSTNAME
,MAX(CASE WHEN indexName='CITY' THEN indexValue END) AS CITY
,MAX(CASE WHEN indexName='STATE' THEN indexValue END) AS [STATE]
FROM DerivedTable
GROUP BY ID
结果
+----+----------+------------+----------+-----------+----------+-----------+
| ID | DOCID | EMPLOYEEID | LASTNAME | FIRSTNAME | CITY | STATE |
+----+----------+------------+----------+-----------+----------+-----------+
| 1 | 49626502 | 248572405 | BROWN | RALPH | PORTLAND | OR |
+----+----------+------------+----------+-----------+----------+-----------+
| 2 | 2222 id | 2222 emp | 222 last | 222 first | 222 city | 222 state |
+----+----------+------------+----------+-----------+----------+-----------+
您可以使用普通PIVOT
:
WITH DerivedTable AS
(
SELECT ID
,f.value('indexName[1]','nvarchar(max)') AS indexName
,f.value('indexValue[1]','nvarchar(max)') AS indexValue
FROM @tbl AS tbl
CROSS APPLY tbl.XmlData.nodes('/Document/Indices/IndexField') AS A(f)
)
SELECT p.*
FROM
(
SELECT * FROM DerivedTable
) AS tbl
PIVOT
(
MAX(indexValue) FOR indexName IN(DOCID,EMPLOYEEID,LASTNAME,FIRSTNAME,CITY,STATE)
) AS p