3

我在 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>

现在我在Table1中插入一个 GUID 列

表格1

   ID   - Name  - Phone  - GUID
   1      HK      999      HJHHKHJHJHKJH8788 
   2      RK      888      OONMNy7878HJHJHSD
   3      SK      777      POMSDHBSNB775SD87
   4      PK      666      HRBMASJMN76448NDN

Table2XML 列中,我想在ID不更改元素名称的情况下使用新的 GUID 值更新节点。

所以现在 XML 将是

   <Root>
    <Data1>
     <ID>HJHHKHJHJHKJH8788</ID>
     <Name>HK</Name> 
     </Data1>
    <Data1>
     <ID>OONMNy7878HJHJHSD</ID>
     <Name>RK</Name>
     </Data1>
    </Root>

这将发生在Table2.

请帮我查询这个。

4

3 回答 3

3

一次在多个地方更新 XML 是不可能的,因此您必须在某种循环中执行此操作。我能想到的最好的办法是从 XML 中提取 IDTable2并加入Table1.ID其中以生成一个临时表,该表包含节点在 XML ( ) 中的Table2.ID序号位置和新值。Data1OrdPosGUID

然后,您可以遍历 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

SQL小提琴

于 2013-08-09T13:51:43.227 回答
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
于 2013-08-08T20:41:41.233 回答
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
于 2013-08-09T14:07:12.600 回答