首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用XML-DML动态定位现有实例中的XML节点

使用XML-DML动态定位现有实例中的XML节点
EN

Stack Overflow用户
提问于 2016-11-04 13:20:49
回答 3查看 1.1K关注 0票数 2

如果可以在Server (2012)中的现有xml实例中动态插入xml节点,我无法找到任何文档。我知道您可以插入或替换一个条件值,但是如果可以根据某些条件动态地完成插入位置,则似乎没有任何文档。例如,假设我有这个XML调用:

代码语言:javascript
复制
SET @xml.modify('insert <SecondaryContact><Name>{ sql:variable("@contactName") }</Name>
                    <Phone>{ sql:variable("@contactPhone") }</Phone>
                    <Email>{ sql:variable("@contactEmail") }</Email></SecondaryContact>
                    after (/Project/PrimaryContact)[1]');

如果after关键字后面列出的节点是有条件的,那么修改是否是有效的语法?以下是我所指的例子:

代码语言:javascript
复制
SET @xml.modify('insert <TechnicalContact><Name>{ sql:variable("@contactName") }</Name>
                    <Phone>{ sql:variable("@contactPhone") }</Phone>
                    <Email>{ sql:variable("@contactEmail") }</Email></TechnicalContact>
                    after (
                        if(count(/Project/SecondaryContact) = 0)
                        then (/Project/PrimaryContact)[1]
                        else (/Project/SecondaryContact)(1)
                    )');

是动态选择在XML语句之外使用IF..ELSE语句的位置的唯一方法,还是我的示例XML有效?

编辑示例XML:

代码语言:javascript
复制
<root>
    ...
    <PrimaryContact Id="1234">
        <Name>John Doe</Name>
        <Phone>555-555-5555</Phone>
        <Email>somewhere@test.com</Email>
    </PrimaryContact>
    <SecondaryContact Id="1236">   <--OPTIONAL
        <Name>John Doe1</Name>
        <Phone>555-555-5556</Phone>
        <Email>somewhere1@test.com</Email>
    </SecondaryContact>
    <TechnicalContact Id="2234"> <--OPTIONAL
        <Name>John Doe2</Name>
        <Phone>555-555-5255</Phone>
        <Email>somewhere3@test.com</Email>
    </TechnicalContact>
    ...
</root>

我知道这个结构不太理想。它应该是<Contacts><Contact Type="PRIMARY" Id="1234">...</Contact>...</Contacts>,但是想知道动态插入位置在DML语句中是否可行。对于这个问题,光标的使用是可以的,就像一次更新一样。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-11-04 15:12:23

这个建议并不完全相同,因为它将在文档后面的任何一个后面插入,而不是在SecondaryContact之后插入,但我怀疑在您的例子中,这是相同的事情:

代码语言:javascript
复制
SET @xml.modify('insert 
    <TechnicalContact><Name>{ sql:variable("@contactName") }</Name>
    <Phone>{ sql:variable("@contactPhone") }</Phone>
    <Email>{ sql:variable("@contactEmail") }</Email></TechnicalContact>

    after (/Project/*[
        local-name(.) = "SecondaryContact" 
        or local-name(.) = "PrimaryContact" 
    ])[last()]
');

或者:

代码语言:javascript
复制
if @xml.value('count(/Project/SecondaryContact)', 'int') = 0
begin
  SET @xml.modify('insert <TechnicalContact><Name>{ sql:variable("@contactName") }</Name>
                <Phone>{ sql:variable("@contactPhone") }</Phone>
                <Email>{ sql:variable("@contactEmail") }</Email></TechnicalContact>
                after (/Project/PrimaryContact)[1]
                ');
end else begin
  SET @xml.modify('insert <TechnicalContact><Name>{ sql:variable("@contactName") }</Name>
                <Phone>{ sql:variable("@contactPhone") }</Phone>
                <Email>{ sql:variable("@contactEmail") }</Email></TechnicalContact>
                after (/Project/SecondaryContact)[1]
                ');
end
票数 4
EN

Stack Overflow用户

发布于 2016-11-04 15:04:45

在您提供更多的示例(请参阅我的注释)之前,我认为最好的方法是创建节点以插入外部,并将其作为最后一个插入。

但是-相当肯定-有更好的方法.

代码语言:javascript
复制
DECLARE @contactName NVARCHAR(100)='TestName';
DECLARE @contactPhone NVARCHAR(100)='TestPhone';
DECLARE @contactEmail NVARCHAR(100)='TestEmail';

DECLARE @tbl TABLE(ID INT IDENTITY,Descr VARCHAR(100),XmlColumn XML);
INSERT INTO @tbl VALUES
 ('With secondary'
 ,N'<Project>
<PrimaryContact>test Primary</PrimaryContact>
<SecondaryContact>test Secondary</SecondaryContact>
</Project>')
,('Only primary'
,N'<Project>
<PrimaryContact id="prim">test Primary</PrimaryContact>
</Project>');

UPDATE @tbl SET XmlColumn.modify
(
    N'insert sql:column("x.NodeToInsert") as last into (/Project)[1]'
)
FROM @tbl
CROSS APPLY
(
    SELECT
    (
        SELECT(
                    SELECT @contactName AS [Name]
                          ,@contactPhone AS [Phone]
                          ,@contactEmail AS [Email]
                    WHERE XmlColumn.exist('/Project/SecondaryContact')=0
                    FOR XML PATH('SecondaryContact'),TYPE
               ) AS [node()]
              ,(
                    SELECT @contactName AS [Name]
                          ,@contactPhone AS [Phone]
                          ,@contactEmail AS [Email]
                    WHERE XmlColumn.exist('/Project/SecondaryContact')=1
                    FOR XML PATH('TechnicalContact'),TYPE
               ) AS [node()]
        FOR XML PATH(''),TYPE
    ) AS NodeToInsert
) AS x

SELECT * FROM @tbl

更新

另一种方法是:使用CTE分解XML,使用.query()获取所有未受影响的节点,使用.value()提取受影响的值。然后用一个简单的选择..。对于XML PATH()语句,以需要的方式重新构建XML .

票数 1
EN

Stack Overflow用户

发布于 2016-11-04 18:43:15

您可以按照这个顺序添加构造序列 of SecondaryContactPrimaryContact,并在第一次出现后添加节点。

代码语言:javascript
复制
insert 
  <TechnicalContact>
    <Name>{ sql:variable("@contactName") }</Name>
    <Phone>{ sql:variable("@contactPhone") }</Phone>
    <Email>{ sql:variable("@contactEmail") }</Email>
  </TechnicalContact>
after (
      /Project/SecondaryContact,
      /Project/PrimaryContact
      )[1]
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40423748

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档