我在SQL Server中有2个表
表1
ID - Name - Phone
1 HK 999
2 RK 888
3 SK 777
4 PK 666
表2
ID - XMLCol
1 XMLVal1
XMLVal1
<Root>
<Data1>
<ID>1</ID>
<Name>HK</Name>
</Data1>
<Data1>
<ID>2</ID>
<Name>RK</Name>
</Data1>
</Root>
现在我将GUID列插入 Table1
表1
ID - Name - Phone - GUID
1 HK 999 HJHHKHJHJHKJH8788
2 RK 888 OONMNy7878HJHJHSD
3 SK 777 POMSDHBSNB775SD87
4 PK 666 HRBMASJMN76448NDN
在Table2
XML列中,我想使用新的GUID值更新ID
节点,而不更改元素名称。
所以现在XML将是
<Root>
<Data1>
<ID>HJHHKHJHJHKJH8788</ID>
<Name>HK</Name>
</Data1>
<Data1>
<ID>OONMNy7878HJHJHSD</ID>
<Name>RK</Name>
</Data1>
</Root>
Table2
中的所有行都会发生这种情况。
请帮我解决此问题。
答案 0 :(得分:3)
不可能一次在多个位置更新XML,因此您必须在某种循环中执行此操作。我能想到的最好的方法是从Table2
中的XML中提取ID并加入Table1.ID
以生成一个临时表,其中包含Table2.ID
Data1
的序号位置XML中的节点(OrdPos
)和新的GUID
值。
然后,您可以循环遍历XML列中存在的最大节点数并执行更新。
-- Variable used to loop over nodes
declare @I int
-- Temp table to hold the work that needs to be done.
create table #T
(
ID int, -- ID from table2
OrdPos int, -- Ordinal position of node Data1 in root
GUID uniqueidentifier, -- New ID
primary key (OrdPos, ID)
)
-- Shred the XML in Table2, join to Table1 to get GUID
insert into #T(ID, OrdPos, GUID)
select T2.ID,
row_number() over(partition by T2.ID order by D.N) as OrdPos,
T1.GUID
from Table2 as T2
cross apply T2.XMLCol.nodes('Root[1]/Data1') as D(N)
inner join Table1 as T1
on T1.ID = D.N.value('(ID/text())[1]', 'int')
-- Get the max number of nodes in one row that needs to be updated
set @I =
(
select top(1) count(*)
from #T
group by ID
order by 1 desc
)
-- Do the updates in a loop, one level at a time
while @I > 0
begin
update T2
set XMLCol.modify('replace value of (/Root[1]/Data1[sql:variable("@I")]/ID/text())[1]
with sql:column("T.GUID")')
from Table2 as T2
inner join #T as T
on T2.ID = T.ID
where T.OrdPos = @I
set @I = @I - 1
end
drop table #T
答案 1 :(得分:0)
我让其中一个更新。
关闭,但没有雪茄。但现在结束了。
IF OBJECT_ID('tempdb..#XmlHolderTable') IS NOT NULL
begin
drop table #XmlHolderTable
end
IF OBJECT_ID('tempdb..#ScalarHolderTable') IS NOT NULL
begin
drop table #ScalarHolderTable
end
CREATE TABLE #ScalarHolderTable
(
ScalarKey int not null ,
Name varchar(16) ,
Phone varchar(16) ,
UUID uniqueidentifier
)
CREATE TABLE #XmlHolderTable
(
XmlSurrogateIdentityKey int not null identity (1001, 1),
TheXml xml
)
INSERT INTO #ScalarHolderTable
( ScalarKey , Name , Phone , UUID )
select 1 , 'HK' , 999 , NEWID()
union all select 2 , 'RK' , 888 , NEWID()
union all select 3 , 'SK' , 777 , NEWID()
union all select 4 , 'PK' , 66 , NEWID()
-- Declare XML variable
DECLARE @data XML;
-- Element-centered XML
SET @data = N'
<Root>
<Data1>
<ID>1</ID>
<Name>HK</Name>
</Data1>
<Data1>
<ID>2</ID>
<Name>RK</Name>
</Data1>
</Root>
';
INSERT INTO #XmlHolderTable ( TheXml) values ( @data )
select TheXml.value('(//Data1/ID)[1]','int') , * from #XmlHolderTable
SELECT Data.Col.value('(.)[1]','Int') AS Id
FROM #XmlHolderTable xmlHolder
CROSS APPLY
TheXml.nodes('//Data1/ID') AS Data(Col)
/*
SELECT Data.Col.value('(Id)[1]','Int') AS Id
FROM @Data.nodes('/Root/Data') AS Data(Col)
*/
declare @counter int
select @counter = 0
/*
WHILE (
exists ( select top 1 null
From
#XmlHolderTable xmlHolder
CROSS APPLY
TheXml.nodes('//Data1/ID') AS Data(Col) , #ScalarHolderTable scalarHolder
Where
ISNUMERIC ( Data.Col.value('(.)[1]','varchar(40)') ) > 0
)
)
BEGIN
select @counter= @counter + 1
print '/@counter/'
print @counter
print ''
*/
UPDATE
#XmlHolderTable
SET
TheXml.modify('replace value of (//Data1/ID/text())[1] with sql:column("scalarHolder.UUID")')
--select Data.Col.value('(.)[1]','Int') as MyValue , scalarHolder.ScalarKey
From
#XmlHolderTable xmlHolder CROSS APPLY TheXml.nodes('//Data1/ID') AS Data(Col)
, #ScalarHolderTable scalarHolder
Where
Data.Col.value('(.)[1]','Int') = scalarHolder.ScalarKey
/*
END
*/
select * from #ScalarHolderTable
select TheXml from #XmlHolderTable
IF OBJECT_ID('tempdb..#XmlHolderTable') IS NOT NULL
begin
drop table #XmlHolderTable
end
IF OBJECT_ID('tempdb..#ScalarHolderTable') IS NOT NULL
begin
drop table #ScalarHolderTable
end
答案 2 :(得分:0)
你绝对想修改当前的xml吗?因为如果你可以从你的数据中生成它,它会更加简单:
update Table2 set
XMLCol =
(
select T1.GUID as ID, T1.Name as Name
from T2.XMLCol.nodes('Root/Data1') as T(C)
inner join Table1 as T1 on
T1.ID = T.C.value('ID[1]', 'int') and
T1.Name = T.C.value('Name[1]', 'varchar(10)')
for xml path('Data1'), root('Root'), type
)
from Table2 as T2
请参阅sql fiddle示例
更新好的,据我所知,每个Data1只有一个ID。然后你可以这样做:
declare @temp table(ID int, T1_ID int, XMLcol xml)
-- split xml, each ID goes in own row
insert into @temp
select ID, T.C.value('ID[1]', 'int') as ID, T.C.query('.') as XMLCol
from Table2 as T2
outer apply T2.XMLCol.nodes('Root/Data1') as T(C)
-- modify xml
update @temp set
XMLCol.modify('
replace value of (Data1/ID/text())[1]
with sql:column("T1.GUID")
')
from @temp as T
inner join Table1 as T1 on T1.ID = T.T1_ID
-- modify original table
update Table2 set
XMLCol =
(
select (select T.XMLcol)
from @temp as T
where T.ID = T2.ID
for xml path(''), root('Root'), type
)
from Table2 as T2