SQL 服务器检索所有值
SQL Server retrieve all values
我有一个 table,我们称它为 TBL
,列类型为 XML
。
XML
列(此处称为 xml
)的格式为:
<START xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="87jjhanM">
<Header xmlns="">
...
</Header>
<Fetch xmlns="">
.....
</Fetch>
<Send xmlns="">
<Supplier>
<Deals>
<Deal>
<Field1> </Field1>
<Field2> </Field2>
</Deal>
</Deals>
</Supplier>
<Supplier>
<Deals>
<Deal>
<Field1> </Field1>
<Field2> </Field2>
</Deal>
</Deals>
</Supplier>
</Send>
</START>
请注意,每个 XML 文档可以有多个 <Supplier>
标签。我感兴趣的是获取 Field1
和 Field2
.
的值
从阅读 How can I query a SQL Server XML column and return all values for a specific node? and Getting multiple records from xml column with value() in SQL Server 看来我应该使用某种交叉应用。
我似乎无法让它发挥作用。使用 value()
,我完全有能力找到第一个实例,但是使用 nodes()
,我惨遭失败(SQL 服务器)。
我为获取所有 Field1 值而进行的公然剽窃尝试(此处仅针对 Field1)是:
SELECT
xml.value('(/Supplier/Deals/Deal/Field1[1])[1]', 'VARCHAR(100)') AS A
FROM
TBL
CROSS APPLY
xml.nodes('/Start/Send') x(A);
据我所知,它只是在每个 /Start/Send/
下查找第一个值 /Supplier/Deals/Deal/Field1
,但它不起作用 - 它只是 returns 0 行受影响(我我应该知道 XML 文件中存在的具体结构。
我相信这很容易,但我就是想不通为什么上面的方法不起作用。非常感谢任何帮助。
有很多错误可能与您的问题没有直接关系:XML 区分大小写(因此 START
,而不是 Start
),外部元素在命名空间 (87jjhanM
) 等需要 WITH XMLNAMESPACES
之类的东西。但假设我们解决了所有问题:
WITH XMLNAMESPACES ('87jjhanM' AS n)
SELECT
A.value('Field1[1]', 'VARCHAR(100)') AS Field1,
A.value('Field2[1]', 'VARCHAR(100)') AS Field2
FROM TBL
CROSS APPLY [xml].nodes('/n:START/Send/Supplier/Deals/Deal') x(A);
理想情况下,CROSS APPLY
应该在我们感兴趣的最低重复元素上完成(在本例中为 Deal
),以使 value
查询尽可能简单,但是这不是硬性要求。
如果您想要 Field1
和 Field2
中的所有值,但您不关心它们实际位于哪个字段,则可以按名称匹配:
WITH XMLNAMESPACES ('87jjhanM' AS n)
SELECT
A.value('.', 'VARCHAR(100)') AS [Field]
FROM TBL
CROSS APPLY [xml].nodes('/n:START/Send/Supplier/Deals/Deal/*[local-name()="Field1" or local-name()="Field2"]') x(A);
如果你想,比如说,获取每个以 Field
开头的元素中的所有内容......那么事情会变得 很多 更烦人,但幸运的是你说你知道所涉及的 XML 的结构,所以这应该不是问题。
为了简洁起见,您试图缩短和清理它,这很好。但是 - 至少我是这么认为的 - 你做的有点过分了......
Jeroen Mostert 已经指向外壳 ("START"!="Start") 和命名空间。第一行有一个(相当奇怪的)默认名称空间,还有一些您根本不用的名称空间。
在你的 XML 中重复 xmlns=""
是非常危险的。这可能是由带有 FOR XML
和子选择的 T-SQL
命令创建的。关键是:这不是只是一些愚蠢的东西可以忽略,而是您正在为内部元素定义一个新的默认命名空间。这就是我使用命名空间通配符 *:
并省略命名空间声明的原因。
我在每个级别添加了一些额外的元素,并假设 <Deals>
下面可以有 1:n
<Supplier>
和 1:n
<Deal>
个节点(在至少命名指向这一点)。您可以为此使用两个级别的 OUTER / CROSS APPLY
:
DECLARE @mockupTBL TABLE(ID INT IDENTITY, TheXml XML);
INSERT INTO @mockupTBL VALUES
(N'<START xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="87jjhanM">
<Header xmlns="">
<SomeNodeWithinHeader SomeValue="blah"/>
</Header>
<Fetch xmlns="">
<SomeNodeWithinFetch SomeValue="blubb"/>
</Fetch>
<Send xmlns="">
<Supplier>
<SupplierRelatedData value="Sup1"/>
<Deals>
<Deal>
<Field1>A1</Field1>
<Field2>A2</Field2>
</Deal>
<Deal>
<Field1>A3</Field1>
<Field2>A4</Field2>
</Deal>
</Deals>
</Supplier>
<Supplier>
<SupplierRelatedData value="Sup2"/>
<Deals>
<Deal>
<Field1>B1</Field1>
<Field2>B2</Field2>
</Deal>
</Deals>
</Supplier>
</Send>
</START>');
SELECT m.TheXml.value(N'(/*:START/Header/SomeNodeWithinHeader/@SomeValue)[1]',N'nvarchar(max)') ValueWithinHeader
,m.TheXml.value(N'(/*:START/Fetch/SomeNodeWithinFetch/@SomeValue)[1]',N'nvarchar(max)') ValueWithinFetch
,sup.value(N'(SupplierRelatedData/@value)[1]',N'nvarchar(max)') SupplierRelatedData
,deal.value(N'(Field1/text())[1]',N'nvarchar(max)') AS Field1
,deal.value(N'(Field2/text())[1]',N'nvarchar(max)') AS Field2
FROM @mockupTBL AS m
OUTER APPLY m.TheXml.nodes(N'/*:START/Send/Supplier') AS A(sup)
OUTER APPLY A.sup.nodes(N'Deals/Deal') AS B(deal)
结果
blah blubb Sup1 A1 A2
blah blubb Sup1 A3 A4
blah blubb Sup2 B1 B2
我有一个 table,我们称它为 TBL
,列类型为 XML
。
XML
列(此处称为 xml
)的格式为:
<START xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="87jjhanM">
<Header xmlns="">
...
</Header>
<Fetch xmlns="">
.....
</Fetch>
<Send xmlns="">
<Supplier>
<Deals>
<Deal>
<Field1> </Field1>
<Field2> </Field2>
</Deal>
</Deals>
</Supplier>
<Supplier>
<Deals>
<Deal>
<Field1> </Field1>
<Field2> </Field2>
</Deal>
</Deals>
</Supplier>
</Send>
</START>
请注意,每个 XML 文档可以有多个 <Supplier>
标签。我感兴趣的是获取 Field1
和 Field2
.
从阅读 How can I query a SQL Server XML column and return all values for a specific node? and Getting multiple records from xml column with value() in SQL Server 看来我应该使用某种交叉应用。
我似乎无法让它发挥作用。使用 value()
,我完全有能力找到第一个实例,但是使用 nodes()
,我惨遭失败(SQL 服务器)。
我为获取所有 Field1 值而进行的公然剽窃尝试(此处仅针对 Field1)是:
SELECT
xml.value('(/Supplier/Deals/Deal/Field1[1])[1]', 'VARCHAR(100)') AS A
FROM
TBL
CROSS APPLY
xml.nodes('/Start/Send') x(A);
据我所知,它只是在每个 /Start/Send/
下查找第一个值 /Supplier/Deals/Deal/Field1
,但它不起作用 - 它只是 returns 0 行受影响(我我应该知道 XML 文件中存在的具体结构。
我相信这很容易,但我就是想不通为什么上面的方法不起作用。非常感谢任何帮助。
有很多错误可能与您的问题没有直接关系:XML 区分大小写(因此 START
,而不是 Start
),外部元素在命名空间 (87jjhanM
) 等需要 WITH XMLNAMESPACES
之类的东西。但假设我们解决了所有问题:
WITH XMLNAMESPACES ('87jjhanM' AS n)
SELECT
A.value('Field1[1]', 'VARCHAR(100)') AS Field1,
A.value('Field2[1]', 'VARCHAR(100)') AS Field2
FROM TBL
CROSS APPLY [xml].nodes('/n:START/Send/Supplier/Deals/Deal') x(A);
理想情况下,CROSS APPLY
应该在我们感兴趣的最低重复元素上完成(在本例中为 Deal
),以使 value
查询尽可能简单,但是这不是硬性要求。
如果您想要 Field1
和 Field2
中的所有值,但您不关心它们实际位于哪个字段,则可以按名称匹配:
WITH XMLNAMESPACES ('87jjhanM' AS n)
SELECT
A.value('.', 'VARCHAR(100)') AS [Field]
FROM TBL
CROSS APPLY [xml].nodes('/n:START/Send/Supplier/Deals/Deal/*[local-name()="Field1" or local-name()="Field2"]') x(A);
如果你想,比如说,获取每个以 Field
开头的元素中的所有内容......那么事情会变得 很多 更烦人,但幸运的是你说你知道所涉及的 XML 的结构,所以这应该不是问题。
为了简洁起见,您试图缩短和清理它,这很好。但是 - 至少我是这么认为的 - 你做的有点过分了......
Jeroen Mostert 已经指向外壳 ("START"!="Start") 和命名空间。第一行有一个(相当奇怪的)默认名称空间,还有一些您根本不用的名称空间。
在你的 XML 中重复 xmlns=""
是非常危险的。这可能是由带有 FOR XML
和子选择的 T-SQL
命令创建的。关键是:这不是只是一些愚蠢的东西可以忽略,而是您正在为内部元素定义一个新的默认命名空间。这就是我使用命名空间通配符 *:
并省略命名空间声明的原因。
我在每个级别添加了一些额外的元素,并假设 <Deals>
下面可以有 1:n
<Supplier>
和 1:n
<Deal>
个节点(在至少命名指向这一点)。您可以为此使用两个级别的 OUTER / CROSS APPLY
:
DECLARE @mockupTBL TABLE(ID INT IDENTITY, TheXml XML);
INSERT INTO @mockupTBL VALUES
(N'<START xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="87jjhanM">
<Header xmlns="">
<SomeNodeWithinHeader SomeValue="blah"/>
</Header>
<Fetch xmlns="">
<SomeNodeWithinFetch SomeValue="blubb"/>
</Fetch>
<Send xmlns="">
<Supplier>
<SupplierRelatedData value="Sup1"/>
<Deals>
<Deal>
<Field1>A1</Field1>
<Field2>A2</Field2>
</Deal>
<Deal>
<Field1>A3</Field1>
<Field2>A4</Field2>
</Deal>
</Deals>
</Supplier>
<Supplier>
<SupplierRelatedData value="Sup2"/>
<Deals>
<Deal>
<Field1>B1</Field1>
<Field2>B2</Field2>
</Deal>
</Deals>
</Supplier>
</Send>
</START>');
SELECT m.TheXml.value(N'(/*:START/Header/SomeNodeWithinHeader/@SomeValue)[1]',N'nvarchar(max)') ValueWithinHeader
,m.TheXml.value(N'(/*:START/Fetch/SomeNodeWithinFetch/@SomeValue)[1]',N'nvarchar(max)') ValueWithinFetch
,sup.value(N'(SupplierRelatedData/@value)[1]',N'nvarchar(max)') SupplierRelatedData
,deal.value(N'(Field1/text())[1]',N'nvarchar(max)') AS Field1
,deal.value(N'(Field2/text())[1]',N'nvarchar(max)') AS Field2
FROM @mockupTBL AS m
OUTER APPLY m.TheXml.nodes(N'/*:START/Send/Supplier') AS A(sup)
OUTER APPLY A.sup.nodes(N'Deals/Deal') AS B(deal)
结果
blah blubb Sup1 A1 A2
blah blubb Sup1 A3 A4
blah blubb Sup2 B1 B2