我有一个表和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;
我的要求:假设此表有一千条记录,我需要搜索<Rating Ratingtype="unknown"> <data> </Rating>
的xml列并将其替换为<SuperRating Ratingtype="unknown"> <data> </SuperRating>
答案 0 :(得分:0)
遗憾的是,这并不容易(至少据我所知......)
这将首先收集所有节点&#34;替换&#34;。将插入这些节点以及相应节点的内容。然后删除原始节点......
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;
答案 1 :(得分:0)
@ 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
答案 2 :(得分:0)
只需在新的查询窗口中复制并执行。
没有简单的事情......您想要替换的节点被带入临时表。在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;