CAST上的XQuery方法为XML,exists()返回0

时间:2017-01-20 00:08:45

标签: sql-server xml sql-server-2008 xquery-sql

查询到sql server 2008,我有一个表,其中一列存储xmldata作为文本,让我们说:

TABLE(identifier varchar(15), xmldata text)

xml看起来有点像这样(注意,没有明确的根元素)

<notRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
  xmlns = "tons.o/NDA/HIPAA/" attribute_1 = "value_1" ... attribute_n = "value_n" >
    <node nAttribute1 = "41pha0000" nAttribute2 = "VALUE" />
</notRoot>

-exactly 1 notRoot,并且每行正好存储1个节点 -trying访问节点属性值
- 这将永远运行,并将极大地伤害它 - (xml将成为其他地方的文本,我需要知道将来如何做到这一点)

所以,为了获取它并让该节点可以作为xml访问(理想情况下,否则我将不得不使用linq或者使其成为可移植的),我将其转换为xml,并尝试使用不同的XQuery关于演员价值的方法。我已经将我观察到的各种行为包含在我的失败中:

select top 1 
 (CAST(l.xmldata as xml)).query('.')             --returns the whole shebang
,(CAST(l.xmldata as xml)).exist('.')             --returns 1
,(CAST(l.xmldata as xml)).exist('(.)[0]')        -- 0, as mentioned below, XML isn't 0 indexed
,(CAST(l.xmldata as xml)).exist('(.)[1]')        -- 1, so this exists
,(CAST(l.xmldata as xml)).exist('/notRoot')      -- 0
,(CAST(l.xmldata as xml)).exist('//notRoot')     -- 0 (sorry ZLK, it was a good idea)
,(CAST(l.xmldata as xml)).exist('/notRoot/node') -- 0
,(CAST(l.xmldata as xml)).exist('(/notRoot)[0]') -- 0, as expected
,(CAST(l.xmldata as xml)).exist('(/notRoot)[1]') -- 0, unfortunate
,(CAST(l.xmldata as xml)).exist('(//notRoot)[1]')-- 0, ditto
from database.dbo.log l

是否没有根元素? 它是否必须存储在xml类型的变量中才能使用此XQuery(以不同方法的MSDN参考为模型)? 任何人都可以向我解释这种行为吗?

1 个答案:

答案 0 :(得分:0)

作为开始:

  • TEXT已被弃用超过15年。未来的版本将不再支持它
  • 如果必须处理XML,则应将其存储在XML类型的列中。真的,如果你能改变这一点,那就去做吧!
  • 在SO上放置关于SQL和XML的问题应始终伴随着一个现实的例子。像<node n_attributes = "n_values" ...>这样的东西对你来说可能很清楚,但对于外部则不然。请阅读我的评论中的问题并提供更多详细信息!

我刚问了我的魔法水晶球,它告诉我,你可能正在寻找这样的东西:

<强>假设

  • 一个条目中有许多<notRoot>个元素
  • 没有实际的<root>元素
  • 属性名称在所有节点中都相同
  • 没有名称空间
  • <node>
  • 只有一个<notRoot>

试试这个:

- 一个声明的虚拟表到模拟你的场景

DECLARE @dummy TABLE(identifier varchar(15), xmldata text);
INSERT INTO @dummy VALUES
('record 1','<notRoot nr_a1 = "nr1_v1" nr_a2="nr1_v2">
                <node n1= "v1" n2="v2" n3="v3"/>
             </notRoot>
             <notRoot nr_a1 = "nr2_v1" nr_a2="nr2_v2">
                <node n1= "a" n2="b" n3="c"/>
             </notRoot>')
,('record 2','<notRoot nr_a1 = "one more" nr_a2="xyz">
                <node n1= "1" n2="2" n3="3"/>
             </notRoot>
             <notRoot nr_a1 = "and even more" nr_a2="more more more">
                <node n1= "100" n2="200" n3="300"/>
             </notRoot>');
WITH Casted AS
(            
    SELECT t.identifier
          ,CAST(t.xmldata AS XML) AS TheXml
    FROM @dummy AS t
)

- 查询

SELECT c.identifier
      ,c.TheXml
      ,nr.value(N'@nr_a1',N'nvarchar(max)') AS notRoot_a1
      ,nr.value(N'@nr_a2',N'nvarchar(max)') AS notRoot_a2
      ,nr.value(N'(node/@n1)[1]',N'nvarchar(max)') AS node_n1
      ,nr.value(N'(node/@n2)[1]',N'nvarchar(max)') AS node_n2
      ,nr.value(N'(node/@n3)[1]',N'nvarchar(max)') AS node_n3
FROM Casted AS c
OUTER APPLY c.TheXml.nodes(N'//notRoot') AS A(nr)

结果:

identifier  notRoot_a1  notRoot_a2       node_n1    node_n2 node_n3
record 1    nr1_v1          nr1_v2          v1      v2       v3
record 1    nr2_v1          nr2_v2          a       b        c
record 2    one more        xyz             1       2        3
record 2    and even more   more more more  100     200      300

更新

根据您的编辑,有一个默认命名空间,必须声明或通配(*:elementname)。

您的编辑看起来更像是您事先不知道属性的数量,也不知道它们的名称。由于<notRoot>中的<node> n属性中可能有n个属性,因此您将获得每个结果。可能会更好地拨打两个不同的电话。

如果您事先知道属性的名称(即使并非所有属性都被所有XML使用,也会更容易......

试试这个:

DECLARE @dummy TABLE(identifier varchar(15), xmldata text);
INSERT INTO @dummy VALUES
('record 1','<notRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns = "tons.o/NDA/HIPAA/" 
              attribute_1 = "value_1" attribute_n = "value_n" >
                  <node nAttribute1 = "41pha0000" nAttribute2 = "VALUE" />
             </notRoot>
             <notRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns = "tons.o/NDA/HIPAA/" 
              attribute_1 = "other" attribute_n = "other_n" >
                  <node nAttribute1 = "xyz" nAttribute2 = "blah" />
             </notRoot>');


WITH XMLNAMESPACES(DEFAULT 'tons.o/NDA/HIPAA/') 
,Casted AS
(            
    SELECT t.identifier
          ,CAST(t.xmldata AS XML) AS TheXml
    FROM @dummy AS t
)
--the query

SELECT Casted.identifier
      ,nrAttr.value(N'local-name(.)',N'nvarchar(max)') AS notRoot_attr_name
      ,nrAttr.value(N'.',N'nvarchar(max)') AS notRoot_attr
      ,ndAttr.value(N'local-name(.)',N'nvarchar(max)') AS notRoot_attr_name
      ,ndAttr.value(N'.',N'nvarchar(max)') AS notRoot_attr
FROM Casted
OUTER APPLY Casted.TheXml.nodes(N'/notRoot/@*') AS A(nr)
OUTER APPLY nr.nodes(N'@*') AS B(nrAttr)
OUTER APPLY nr.nodes(N'node') AS C(nd)
OUTER APPLY nd.nodes(N'@*') AS D(ndAttr)

结果

record 1    attribute_1 value_1 nAttribute1 41pha0000
record 1    attribute_1 value_1 nAttribute2 VALUE
record 1    attribute_n value_n nAttribute1 41pha0000
record 1    attribute_n value_n nAttribute2 VALUE
record 1    attribute_1 other   nAttribute1 xyz
record 1    attribute_1 other   nAttribute2 blah
record 1    attribute_n other_n nAttribute1 xyz
record 1    attribute_n other_n nAttribute2 blah