我有一个SQL文件表,其中存储了多个xml文件供SQL使用。 xml文件的内容不在我的控制范围内。我只需要将它们用作表的输入即可。 所有xml文件都具有相同的结构/设置。唯一的问题是,我刚刚意识到其中一些xml文件具有不同的名称空间url(因此在我的表中返回了NULL)。
我正在使用xml文件创建一个表,其中xml的键作为列返回,属性作为值在行中返回。每个xml作为行返回。
所以我现在遇到的问题是,对于名称空间(略有不同)的所有xml,整个行都将返回NULL。
使用的名称空间是: http://schemas.kvk.nl/xb/query/service/2016/1/0/0 和 http://schemas.kvk.nl/xb/query/service/2017/1/0/0
我使用的查询:
WITH XMLNAMESPACES('http://schemas.kvk.nl/xb/query/service/2016/1/0/0' AS ns2) -- Pull namespaces for NS2
SELECT p.*
FROM
(
SELECT [name]
,x.l.value('(ns2:opendataField[@key="SbiBusinessCode"]/@value)[1]','varchar(max)') AS SBI
,x.l.value('(ns2:opendataField[@key="FinancialYear"]/@value)[1]','varchar(max)') AS FY
from dbo.XBRLft t -- filestream table
CROSS APPLY(SELECT CAST(t.[file_stream] AS XML)) A(xbrl) -- convert filestream into xml.
CROSS APPLY xbrl.nodes('/opendata') x(l)
where x.l.exist('./*/@key')=1
) p
这将返回仅包含第一个名称空间的值的表(因为在查询中使用了该值),但是基于具有第二个名称空间的xml的每一行都将返回null。
因此,我尝试使用通配符代替名称空间,但这只会返回错误。
SELECT p.*
FROM
(
SELECT [name]
-- Putting all key's as columns and showing the attribute value in row.
,x.l.value('(//*:ns2:opendataField[@key="FinancialYear"]/@value)[1]','varchar(max)') AS FY
from dbo.XBRLft t -- filestream table
CROSS APPLY(SELECT CAST(t.[file_stream] AS XML)) A(xbrl) --
CROSS APPLY xbrl.nodes('//*:opendata') x(l) --
where x.l.exist('./*/@key')=1 --
) p
查询中还有很多键,但在此示例中省略了这些键。
有什么主意,我可以通过应用2个名称空间url或通配符修复程序来实现此目的吗?
答案 0 :(得分:1)
需要使用命名空间来避免同名之间的歧义。从这个角度来看,使用通配符可能非常危险,并且可能导致意外结果...
尝试一下:
带有一些测试数据的虚拟表
DECLARE @tbl TABLE(id INT IDENTITY, YourXml XML);
INSERT INTO @tbl VALUES
('<root xmlns="blah1">
<test>Test in 1</test>
</root>'),
('<root xmlns="blah2">
<test>Test in 2</test>
</root>');
-这是您的问题:我们定义了默认名称空间,该名称空间仅适用于案例1:
WITH XMLNAMESPACES(DEFAULT 'blah1')
SELECT t.id
,t.YourXml.value('(/root/test/text())[1]','nvarchar(100)') AS ContentOfTest
FROM @tbl t;
-但是我们可以使用两个带前缀的名称空间,并使用COALESCE返回一个返回值的名称空间:
WITH XMLNAMESPACES('blah1' AS ns1
,'blah2' AS ns2)
SELECT t.id
,COALESCE(
t.YourXml.value('(/ns1:root/ns1:test/text())[1]','nvarchar(100)')
,t.YourXml.value('(/ns2:root/ns2:test/text())[1]','nvarchar(100)')
) AS ContentOfTest
FROM @tbl t
-这是使用通配符的方式,如果可以确定,这不会导致歧义:
SELECT t.id
,t.YourXml.value('(/*:root/*:test/text())[1]','nvarchar(100)') AS ContentOfTest
FROM @tbl t