【问题标题】:XML DML Script to replace nodes用于替换节点的 XML DML 脚本
【发布时间】:2016-03-28 17:25:34
【问题描述】:

我有一个表格和xml数据,例如:

                IF EXISTS(
                  SELECT table_name FROM information_schema.tables 
                  WHERE table_name = 'JobCandidates')
                DROP TABLE JobCandidates;
                -- Create JobCandidates table 
                CREATE TABLE JobCandidates(
                  CandidateId INT PRIMARY KEY,
                -- Create typed XML column
                  CandidateResume XML 
                    (DOCUMENT HumanResources.HRResumeSchemaCollection) NULL,
                -- Create untyped XML column
                  CandidateRating XML NULL);
                -- Insert data into the typed column
                INSERT INTO JobCandidates (CandidateId, CandidateResume)
                  (SELECT JobCandidateId, [Resume]
                  FROM HumanResources.JobCandidate
                  WHERE JobCandidateId = 1);
                UPDATE JobCandidates
                SET CandidateRating =
                  '<Ratings>       
                    <Rating Ratingtype="unknown">       
                      <AppliedKnowledge>3.0</AppliedKnowledge>       
                      <ToolSkills>3.5</ToolSkills>       
                    </Rating>       
                    <Rating Ratingtype="known">       
                      <Experience>9.5</Experience>       
                      <Education>16.0</Education>       
                      <DbDevelopment>4.5</DbDevelopment>       
                    </Rating>
                      <Rating Ratingtype="unknown">       
                      <AppliedKnowledge>4.0</AppliedKnowledge>       
                      <ToolSkills>4.5</ToolSkills>       
                    </Rating>       
                  </Ratings>';
                SELECT * FROM JobCandidates;

我的要求:假设这张表有一千条记录,我需要搜索&lt;Rating Ratingtype="unknown"&gt; &lt;data&gt; &lt;/Rating&gt;的xml列并将其替换为&lt;SuperRating Ratingtype="unknown"&gt; &lt;data&gt; &lt;/SuperRating&gt;

【问题讨论】:

  • 假设这个表有数千条记录,我需要搜索 xml 并将其替换为
  • 欢迎来到 StackOverflow!你可以编辑问题来完成它,目前还不清楚你在问什么
  • 嗨 Raj,如果您想显示 XML,您必须将其格式化为代码(带反引号)
  • 嗨,Raj,欢迎来到 SO!由于您是新手,请允许我提示:您提出了一个问题,我花了很多时间来回答它,然后由于您的补充而再次回答。如果您找到了自己的解决方案,您应该为未来的读者提供一个自我回答。如果您不再需要任何答案,请发表简短评论。如果您对我的回答有疑问,请说明一些细节,我很乐意提供帮助。如果我的回答解决了您的问题,请勾选验收。还有please read this: someone-answers.

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


【解决方案1】:

编辑

遗憾的是,这并不容易(至少据我所知......)

这将首先收集所有要“替换”的节点。这些节点将插入相应节点的内容。然后把原来的节点去掉……

感谢 Mikael Eriksson:https://stackoverflow.com/a/15682327/5089204

SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RowIndex
      ,ROW_NUMBER() OVER(PARTITION BY CandidateId ORDER BY (SELECT NULL)) AS NodeIndex
      ,CandidateId
INTO #tmpNodesToReplace
FROM #JobCandidates
CROSS APPLY CandidateRating.nodes('/Ratings/Rating[@Ratingtype="unknown"]') AS A(B);

DECLARE @I INT=1;
DECLARE @CountNodes INT=(SELECT COUNT(*) FROM #tmpNodesToReplace);
WHILE 1 = 1
BEGIN
    UPDATE #JobCandidates
    SET CandidateRating.modify('insert <SuperRating>{(/Ratings/Rating[@Ratingtype="unknown"])[sql:column("NodeIndex")]/*}</SuperRating> into (/Ratings)[1]')
    FROM #JobCandidates
    INNER JOIN #tmpNodesToReplace ON #JobCandidates.CandidateId = #tmpNodesToReplace.CandidateId
    WHERE #tmpNodesToReplace.RowIndex=@I;

  IF @I>@CountNodes
    BREAK;

  SET @I = @I + 1
END

UPDATE #JobCandidates
SET CandidateRating.modify('delete /Ratings/Rating[@Ratingtype="unknown"]');

上一页

我简化了您的示例以向您展示一般方法。请通过添加与我的示例的 XML 部分相对应的预期输出来解释您要修改的内容:

CREATE TABLE #JobCandidates(
    CandidateId INT PRIMARY KEY,
    CandidateRating XML NULL);

INSERT INTO #JobCandidates (CandidateId, CandidateRating) VALUES
 (1 -- test row with two "unknown" Ratings
  ,'<Ratings>       
    <Rating Ratingtype="unknown">       
        <AppliedKnowledge>3.0</AppliedKnowledge>       
        <ToolSkills>3.5</ToolSkills>       
    </Rating>       
    <Rating Ratingtype="known">       
        <Experience>9.5</Experience>       
        <Education>16.0</Education>       
        <DbDevelopment>4.5</DbDevelopment>       
    </Rating>
        <Rating Ratingtype="unknown">       
        <AppliedKnowledge>4.0</AppliedKnowledge>       
        <ToolSkills>4.5</ToolSkills>       
    </Rating>       
    </Ratings>')
, (2 --test row with one "unknown" Rating
  ,'<Ratings>       
    <Rating Ratingtype="other than unknown">       
        <AppliedKnowledge>3.0</AppliedKnowledge>       
        <ToolSkills>3.5</ToolSkills>       
    </Rating>       
    <Rating Ratingtype="known">       
        <Experience>9.5</Experience>       
        <Education>16.0</Education>       
        <DbDevelopment>4.5</DbDevelopment>       
    </Rating>
        <Rating Ratingtype="unknown">       
        <AppliedKnowledge>4.0</AppliedKnowledge>       
        <ToolSkills>4.5</ToolSkills>       
    </Rating>       
    </Ratings>')
, (3 --test row with n "unknown" Rating
  ,'<Ratings>       
    <Rating Ratingtype="other than unknown">       
        <AppliedKnowledge>3.0</AppliedKnowledge>       
        <ToolSkills>3.5</ToolSkills>       
    </Rating>       
    <Rating Ratingtype="known">       
        <Experience>9.5</Experience>       
        <Education>16.0</Education>       
        <DbDevelopment>4.5</DbDevelopment>       
    </Rating>
        <Rating Ratingtype="other than unknown">       
        <AppliedKnowledge>4.0</AppliedKnowledge>       
        <ToolSkills>4.5</ToolSkills>       
    </Rating>       
    </Ratings>');

--Find rows with any "unknown" ratings
SELECT * FROM #JobCandidates
WHERE CandidateRating.exist('/Ratings/Rating[@Ratingtype="unknown"]')=1;

--Find all rows with "unknown" (ID=1 showing 2 entries
SELECT CandidateId
      ,A.B.query('.') 
FROM #JobCandidates
CROSS APPLY CandidateRating.nodes('/Ratings/Rating[@Ratingtype="unknown"]') AS A(B);

DROP TABLE #JobCandidates;

【讨论】:

  • 谢谢@shnugo。现在我想用''和''替换节点'' ''> 用于该特定节点
  • 不,在脚本执行之前 XML 对我不起作用:3.03.59.516.04.54.0 AppliedKnowledge> 4.5
  • @Raj “没用”还不够……什么没用?错误?输出错误?您发布的 XML 的预期结果是什么?
【解决方案2】:

@shnugo..thnks 输入。这是我最终完成所需工作的脚本。不知道有没有比这更简单的方法

            CREATE TABLE #JobCandidates(
                CandidateId INT PRIMARY KEY,
                CandidateRating XML NULL);

            INSERT INTO #JobCandidates (CandidateId, CandidateRating) VALUES
             (1 -- test row with two "unknown" Ratings
              ,'<Ratings>       
                <Rating Ratingtype="unknown">       
                    <AppliedKnowledge>3.0</AppliedKnowledge>       
                    <ToolSkills>3.5</ToolSkills>       
                </Rating>       
                <Rating Ratingtype="known">       
                    <Experience>9.5</Experience>       
                    <Education>16.0</Education>       
                    <DbDevelopment>4.5</DbDevelopment>       
                </Rating>
                    <Rating Ratingtype="unknown">       
                    <AppliedKnowledge>4.0</AppliedKnowledge>       
                    <ToolSkills>4.5</ToolSkills>       
                </Rating>       
                </Ratings>')
            , (2 --test row with one "unknown" Rating
              ,'<Ratings>       
                <Rating Ratingtype="other than unknown">       
                    <AppliedKnowledge>3.0</AppliedKnowledge>       
                    <ToolSkills>3.5</ToolSkills>       
                </Rating>       
                <Rating Ratingtype="known">       
                    <Experience>9.5</Experience>       
                    <Education>16.0</Education>       
                    <DbDevelopment>4.5</DbDevelopment>       
                </Rating>
                    <Rating Ratingtype="unknown">       
                    <AppliedKnowledge>4.0</AppliedKnowledge>       
                    <ToolSkills>4.5</ToolSkills>       
                </Rating>       
                </Ratings>')
            , (3 --test row with n "unknown" Rating
              ,'<Ratings>       
                <Rating Ratingtype="other than unknown">       
                    <AppliedKnowledge>3.0</AppliedKnowledge>       
                    <ToolSkills>3.5</ToolSkills>       
                </Rating>       
                <Rating Ratingtype="known">       
                    <Experience>9.5</Experience>       
                    <Education>16.0</Education>       
                    <DbDevelopment>4.5</DbDevelopment>       
                </Rating>
                    <Rating Ratingtype="other than unknown">       
                    <AppliedKnowledge>4.0</AppliedKnowledge>       
                    <ToolSkills>4.5</ToolSkills>       
                </Rating>       
                </Ratings>');

            --Find rows with any "unknown" ratings
            SELECT * FROM #JobCandidates
            WHERE CandidateRating.exist('/Ratings/Rating[@Ratingtype="unknown"]')=1;

            --Find all rows with "unknown" (ID=1 showing 2 entries
            SELECT CandidateId
                  ,A.B.query('.') 
            FROM #JobCandidates
            CROSS APPLY CandidateRating.nodes('/Ratings/Rating[@Ratingtype="unknown"]') AS A(B);

            --change '<Rating Ratingtype="unknown">' to '<SuperRating Ratingtype="unknown">
            SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RowIndex
                  ,ROW_NUMBER() OVER(PARTITION BY CandidateId ORDER BY (SELECT NULL)) AS NodeIndex
                  ,CandidateId
            INTO #tmpNodesToReplace
            FROM #JobCandidates
            CROSS APPLY CandidateRating.nodes('/Ratings/Rating[@Ratingtype="unknown"]') AS A(B);

            DECLARE @I INT=1;
            DECLARE @CountNodes INT=(SELECT COUNT(*) FROM #tmpNodesToReplace);
            WHILE 1 = 1
            BEGIN
             UPDATE #JobCandidates
                SET CandidateRating.modify('insert <SuperRating Ratingtype="unknown">{(/Ratings/Rating[@Ratingtype="unknown"])[sql:column("NodeIndex")]/*}</SuperRating> before (//Rating)[1]')
                FROM #JobCandidates
                INNER JOIN #tmpNodesToReplace ON #JobCandidates.CandidateId = #tmpNodesToReplace.CandidateId
                WHERE #tmpNodesToReplace.RowIndex=@I;



                update #JobCandidates set
                CandidateRating.modify('replace value of (/Ratings/Rating/@Ratingtype)[1] with "delete"')
                FROM #JobCandidates INNER JOIN #tmpNodesToReplace ON #JobCandidates.CandidateId = #tmpNodesToReplace.CandidateId
                WHERE #tmpNodesToReplace.RowIndex=@I;

                UPDATE #JobCandidates
                SET CandidateRating.modify('delete /Ratings/Rating[@Ratingtype="delete"]') FROM #JobCandidates where CandidateRating is not null ;

              IF @I>@CountNodes
                BREAK;

              SET @I = @I + 1
            END

            --drop table #JobCandidates
            --drop table #tmpNodesToReplace
            --select * from #JobCandidates

【讨论】:

  • 这不是我的代码吗?抱歉,我不明白……这是您为未来读者提供的解决方案还是您需要帮助的一些代码?
【解决方案3】:

只需将其复制到新的查询窗口中并执行即可。

这并不容易...您要替换的节点被放入临时表中。在 WHILE 循环中,它们作为新节点插入,而旧节点被删除。 XML-DML 不允许一次执行多个操作...

CREATE TABLE #JobCandidates(
    CandidateId INT PRIMARY KEY,
    CandidateRating XML NULL);

INSERT INTO #JobCandidates (CandidateId, CandidateRating) VALUES
 (1 -- test row with two "unknown" Ratings
  ,'<Ratings>
  <Rating Ratingtype="unknown">
    <AppliedKnowledge>3.0</AppliedKnowledge>
    <ToolSkills>3.5</ToolSkills>
  </Rating>
  <Rating Ratingtype="known">
    <Experience>9.5</Experience>
    <Education>16.0</Education>
    <DbDevelopment>4.5</DbDevelopment>
  </Rating>
  <Rating Ratingtype="unknown">
    <AppliedKnowledge>4.0</AppliedKnowledge>
    <ToolSkills>4.5</ToolSkills>
  </Rating>
</Ratings>');

SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RowIndex
      ,ROW_NUMBER() OVER(PARTITION BY CandidateId ORDER BY (SELECT NULL)) AS NodeIndex
      ,CandidateId
INTO #tmpNodesToReplace
FROM #JobCandidates
CROSS APPLY CandidateRating.nodes('/Ratings/Rating[@Ratingtype="unknown"]') AS A(B);

DECLARE @I INT=1;
DECLARE @CountNodes INT=(SELECT COUNT(*) FROM #tmpNodesToReplace);
WHILE 1 = 1
BEGIN
    UPDATE #JobCandidates
    SET CandidateRating.modify('insert <SuperRating>{(/Ratings/Rating[@Ratingtype="unknown"])[sql:column("NodeIndex")]/*}</SuperRating> into (/Ratings)[1]')
    FROM #JobCandidates
    INNER JOIN #tmpNodesToReplace ON #JobCandidates.CandidateId = #tmpNodesToReplace.CandidateId
    WHERE #tmpNodesToReplace.RowIndex=@I;

  IF @I>@CountNodes
    BREAK;

  SET @I = @I + 1
END

UPDATE #JobCandidates
SET CandidateRating.modify('delete /Ratings/Rating[@Ratingtype="unknown"]');

SELECT * FROM #JobCandidates;

/* Both "Unknown" Ratings are replaced
<Ratings>
  <Rating Ratingtype="known">
    <Experience>9.5</Experience>
    <Education>16.0</Education>
    <DbDevelopment>4.5</DbDevelopment>
  </Rating>
  <SuperRating>
    <AppliedKnowledge>3.0</AppliedKnowledge>
    <ToolSkills>3.5</ToolSkills>
  </SuperRating>
  <SuperRating>
    <AppliedKnowledge>4.0</AppliedKnowledge>
    <ToolSkills>4.5</ToolSkills>
  </SuperRating>
</Ratings>
*/

DROP TABLE #tmpNodesToReplace;
DROP TABLE #JobCandidates;

【讨论】:

    猜你喜欢
    • 2017-10-20
    • 1970-01-01
    • 2015-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-27
    • 1970-01-01
    • 2018-03-05
    相关资源
    最近更新 更多