我想在一个表中更改2列的值。一列是varchar,另一列是XML。首先,我想用新值替换RECIPIENT列的值,并用新值RecipientNo替换XML列中名为RecipientNo的节点值。如何在同一更新功能中执行这两项操作?下面的查询有效。其次,DATARECORD表包含太多记录。修改功能是否花费太多时间来更新记录?如果是这样,我如何提高修改功能的性能,或者您可以建议其他替代解决方案?顺便说一句,我不能将索引添加到DATARECORD表。谢谢。
这里是示例行;
ID RECIPIENT RECORDDETAILS
1 1 <?xml version="1.0"?>
<MetaTag xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/XMLSchema">
<Code>123</Code>
<RecipientNo>123</RecipientNo>
<Name>xyz</Name>
</MetaTag>'
CREATE TABLE #TEMPTABLE(
ID bigint,
RECIPIENT nvarchar(max),
RECORDDETAILS xml
)
INSERT INTO #TEMPTABLE
SELECT ID,RECIPIENT,RECORDDETAILS
FROM DATARECORD WITH (NOLOCK)
WHERE cast(RECORDDETAILS as varchar(max)) LIKE '%<Code>123</Code>%' and cast(RECORDDETAILS as varchar(max)) LIKE '%MetaTag%'
UPDATE #TEMPTABLE SET RECIPIENT = CONCAT('["queryType|1","recipientNoIDENTIFICATION|',RECIPIENT,']')
UPDATE #TEMPTABLE SET RECORDDETAILS.modify('replace value of (MetaTag/RecipientNo/text())[1] with sql:column("RECIPIENT")')
UPDATE d
SET d.RECORDDETAILS =Concat('<?xml version="1.0"?>', CAST(t.RECORDDETAILS AS VARCHAR(max))),
d.RECIPIENT = t.RECIPIENT
FROM dbo.DATARECORD as d
Join #TEMPTABLE as t
ON t.ID = d.ID
当然可以在同一条更新语句中更新SQL列和XML节点,例如:
create table DataRecord (
ID bigint not null primary key,
Recipient nvarchar(max) not null,
RecordDetails xml not null
);
insert DataRecord values
(1, N'1', N'<?xml version="1.0"?>
<MetaTag xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/XMLSchema">
<Code>123</Code>
<RecipientNo>123</RecipientNo>
<Name>xyz</Name>
</MetaTag>');
create table #TempTable (
ID bigint not null primary key,
Recipient nvarchar(max) not null,
RecordDetails xml not null
);
insert #TempTable
select ID, Recipient, RecordDetails
from DataRecord with (nolock)
where cast(RecordDetails as varchar(max)) like '%<Code>123</Code>%' and cast(RecordDetails as varchar(max)) like '%MetaTag%'
-- Change an SQL value and an XML node in the one update statement...
update tt set
Recipient = NewRecipient,
RecordDetails.modify('replace value of (/MetaTag/RecipientNo/text())[1] with sql:column("NewRecipient")')
from #TempTable tt
outer apply (
select NewRecipient = concat('["queryType|1","recipientNoIDENTIFICATION|', Recipient, '"]')
) Calc
select * from #TempTable
哪个产量:
ID Recipient RecordDetails
1 ["queryType|1","recipientNoIDENTIFICATION|1"] <MetaTag
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/XMLSchema">
<Code>123</Code>
<RecipientNo>["queryType|1","recipientNoIDENTIFICATION|1"]</RecipientNo>
<Name>xyz</Name>
</MetaTag>
有几件事导致您的性能问题:
like
匹配(转换为varchar)将导致TABLE SCAN操作,转换和测试表中的每一行。要考虑的一些事情:
RecordDetails
列,并使用类似WHERE RecordDetails.exists('/MetaTag/Code[.="123"])
的名称来短列出要更新的行。RecordDetails
预切碎,将/MetaTag/Code/text()
的值保留在表列中(例如:MetaTagCode
),并在查询中使用类似WHERE MetaTagCode='123'
的内容。向该列添加索引将使SQL在搜索所需值(而不是表扫描)时执行便宜得多的INDEX SCAN。由于您说无法添加索引,因此基本上必须忍受TABLE SCAN,然后等待它。