如何在不将列类型更改为“xml”的情况下在“ntext”列上使用“修改”方法(使用 CAST 或 CONVERT 或其他方法)
How to use `modify` method on a `ntext` column without changing column type to `xml` (using CAST or CONVERT or other method)
我需要更新存储在名为 data
的 ntext
列中的 XML 内容中的两个属性
我尝试使用 xml.modify
XQuery 方法,在 data
列上使用 CAST
或 CONVERT
,但没成功:
当尝试使用 CAST
UPDATE [dbo].[CodeSystemCodes_data]
SET
(CAST([data] as xml)).modify('replace value of (/Utilities.CodeSystems.CodeSystemCodes/@Description)[1] with sql:variable("@NEW_EXAM_NAME")')
WHERE [data] like '%' + @CURRENT_EXAM_CODE + '%'
我收到这个错误
Incorrect syntax near '('
...在 CAST 之前,删除“(”也会失败
我最终创建了一个名为 xmlData
的具有单个 XML
类型列的临时 table,在该 table 上使用了修改方法,然后将数据返回到原始数据table,但这似乎有点矫枉过正
如何在不使用任何类型的中介 table 的情况下使用 ntext
类型的 data
列的 modify
方法?也许使用 CAST 或 CONVERT 或其他东西。我尝试使用和 XML 变量也没有成功。
请记住,此时更改列类型是不可能的,因为我不是 DBA,也不是有决定权的人。
我正在使用 XML 修改方法而不是 REPLACE,因为我不想沿着 XML 数据进行错误的替换。
还有其他类似的问题,但目前都没有答案
How to update XML in ntext column?
Inserting data to ntext xml column (Cannot call methods on ntext error)
代码:
DECLARE @NEW_EXAM_NAME NVARCHAR(10) = 'BCC'
DECLARE @CODE_DESC NVARCHAR(50)
SET @CODE_DESC = @CURRENT_EXAM_CODE + ' - ' + @NEW_EXAM_NAME
CREATE TABLE #temp_xml (xmlData XML)
INSERT INTO #temp_xml
SELECT CAST([data] AS XML)
FROM [dbo].[CodeSystemCodes_data]
WHERE [data] LIKE '%' + @CURRENT_EXAM_CODE + '%'
UPDATE #temp_xml
SET xmlData.modify('replace value of (/Utilities.CodeSystems.CodeSystemCodes/@Description)[1] with sql:variable("@NEW_EXAM_NAME")')
UPDATE #temp_xml
SET xmlData.modify('replace value of (/Utilities.CodeSystems.CodeSystemCodes/@CodeAndDescription)[1] with sql:variable("@CODE_DESC")')
SELECT * FROM #temp_xml
UPDATE [dbo].[CodeSystemCodes_data]
SET [data] = CAST(CAST((SELECT xmlData FROM #temp_xml) as nvarchar(max)) as ntext)
WHERE [data] LIKE '%' + @CURRENT_EXAM_CODE + '%'
DROP TABLE #temp_xml
不幸的是,当您的 XML 存储为文本时,您几乎无法执行类似于您所执行的操作。
如果你想摆脱对临时表的使用,你可以尝试这样的事情。您可以在 SSMS 中 运行 这个。
/* Base table mock-up */
DECLARE @Data TABLE ( [data] NTEXT, [id] INT IDENTITY (1,1) );
INSERT INTO @Data ( [data] ) VALUES
( '<root><values><val>Value 1</val><val>to_be_changed</val></values></root>' ),
( '<root><values><val>All is well here.</val><val>All is well here, too.</val></values></root>' ),
( '<root><values><val>Another value.</val><val>to_be_changed</val></values></root>' );
/* Find/Replace variables */
DECLARE
@find_value VARCHAR(50) = 'to_be_changed',
@replace_value VARCHAR(50) = 'Value 2';
/* Create a table variable to temporarily house the ntext data as xml so the XML may be modified */
DECLARE @Temp TABLE ( DataXml XML, id INT );
/* Insert [data] into the XML column */
INSERT INTO @Temp ( DataXml, [id] )
SELECT CAST ( [data] AS XML ), [id] FROM @Data WHERE [data] LIKE '%' + @find_value + '%';
/* Show the @Data resultset before modifying */
SELECT * FROM @Data;
/* The WHILE is to make sure every node that requires updating gets updated */
/* Modify each instance matching the @find_value criteria */
WHILE EXISTS ( SELECT * FROM @Temp WHERE DataXml.exist( '//root/values/val/text()[.=sql:variable("@find_value")]' ) = 1 )
UPDATE @Temp
SET
DataXml.modify ('
replace value of (/root/values/val/text()[.=sql:variable("@find_value")])[1]
with sql:variable("@replace_value")
');
/* Update the results back to the ntext column */
UPDATE @Data
SET
[data] = CAST ( t.DataXml AS NVARCHAR(MAX) )
FROM @Data d
INNER JOIN @Temp t
ON d.id = t.id;
/* Show the updated @Data resultset */
SELECT * FROM @Data;
@Data的初始select:
/* Show the @Data resultset before modifying */
SELECT * FROM @Data;
Returns
+---------------------------------------------------------------------------------------------+----+
| data | id |
+---------------------------------------------------------------------------------------------+----+
| <root><values><val>Value 1</val><val>to_be_changed</val></values></root> | 1 |
| <root><values><val>All is well here.</val><val>All is well here, too.</val></values></root> | 2 |
| <root><values><val>Another value.</val><val>to_be_changed</val></values></root> | 3 |
+---------------------------------------------------------------------------------------------+----+
@Data 的最终结果集:
/* Show the updated @Data resultset */
SELECT * FROM @Data;
Returns
+---------------------------------------------------------------------------------------------+----+
| data | id |
+---------------------------------------------------------------------------------------------+----+
| <root><values><val>Value 1</val><val>Value 2</val></values></root> | 1 |
| <root><values><val>All is well here.</val><val>All is well here, too.</val></values></root> | 2 |
| <root><values><val>Another value.</val><val>Value 2</val></values></root> | 3 |
+---------------------------------------------------------------------------------------------+----+
可能的替代方法:
也许在您的文本中添加一个简单的 REPLACE
。
UPDATE @Data
SET
[data] = REPLACE ( CAST ( [data] AS NVARCHAR(MAX) ), @find_value, @replace_value )
FROM @Data d
WHERE
d.[data] LIKE '%' + @find_value + '%';
更新:
我应该更清楚地说“我不想使用任何类型的中间表”
/* For-each find/replace instance found... */
WHILE EXISTS ( SELECT * FROM @Data WHERE CAST ( [data] AS XML ).exist( '//root/values/val/text()[.=sql:variable("@find_value")]' ) = 1 )
BEGIN
DECLARE @id INT, @xml XML;
SELECT TOP 1
@id = id,
@xml = CAST ( [data] AS XML )
FROM @Data
WHERE CAST ( [data] AS XML ).exist( '//root/values/val/text()[.=sql:variable("@find_value")]' ) = 1;
-- Modify the XML --
SET @xml.modify('
replace value of (/root/values/val/text()[.=sql:variable("@find_value")])[1]
with sql:variable("@replace_value")
');
-- Update the modified XML --
UPDATE @Data
SET
[data] = CAST ( @xml AS NVARCHAR(MAX) )
WHERE id = @id;
END
/* Show the updated resultset */
SELECT * FROM @Data ORDER BY id;
更新结果集:
+---------------------------------------------------------------------------------------------+----+
| data | id |
+---------------------------------------------------------------------------------------------+----+
| <root><values><val>Value 1</val><val>Value 2</val><val>Value 2</val></values></root> | 1 |
| <root><values><val>All is well here.</val><val>All is well here, too.</val></values></root> | 2 |
| <root><values><val>Another value.</val><val>Value 2</val></values></root> | 3 |
+---------------------------------------------------------------------------------------------+----+
OP更新
感谢您最后的解决方案,我最终这样做了,不需要 while 循环
DECLARE @CURRENT_EXAM_CODE NVARCHAR(10) = 'BXC_14B'
DECLARE @NEW_EXAM_NAME NVARCHAR(10) = 'BCC'
DECLARE @CODE_DESC NVARCHAR(50)
DECLARE @XML_DATA XML
-- convert existing NTEXT data into XML
SELECT @XML_DATA =
CAST([data] as xml)
FROM [dbo].[CodeSystemCodes_data]
WHERE [data] like '%' + @CURRENT_EXAM_CODE + '%'
-- update the xml data
SET @XML_DATA.modify('replace value of (/Utilities.CodeSystems.CodeSystemCodes/@Description)[1] with sql:variable("@NEW_EXAM_NAME")')
SET @CODE_DESC = @CURRENT_EXAM_CODE + ' - ' + @NEW_EXAM_NAME
SET @XML_DATA.modify('replace value of (/Utilities.CodeSystems.CodeSystemCodes/@CodeAndDescription)[1] with sql:variable("@CODE_DESC")')
-- convert xml data back to ntext type
UPDATE [dbo].[CodeSystemCodes_data]
SET
[data] = CAST(CAST(@XML_DATA as nvarchar(max)) as ntext)
WHERE [data] like '%' + @CURRENT_EXAM_CODE + '%'
我需要更新存储在名为 data
ntext
列中的 XML 内容中的两个属性
我尝试使用 xml.modify
XQuery 方法,在 data
列上使用 CAST
或 CONVERT
,但没成功:
当尝试使用 CAST
UPDATE [dbo].[CodeSystemCodes_data]
SET
(CAST([data] as xml)).modify('replace value of (/Utilities.CodeSystems.CodeSystemCodes/@Description)[1] with sql:variable("@NEW_EXAM_NAME")')
WHERE [data] like '%' + @CURRENT_EXAM_CODE + '%'
我收到这个错误
Incorrect syntax near '('
...在 CAST 之前,删除“(”也会失败
我最终创建了一个名为 xmlData
的具有单个 XML
类型列的临时 table,在该 table 上使用了修改方法,然后将数据返回到原始数据table,但这似乎有点矫枉过正
如何在不使用任何类型的中介 table 的情况下使用 ntext
类型的 data
列的 modify
方法?也许使用 CAST 或 CONVERT 或其他东西。我尝试使用和 XML 变量也没有成功。
请记住,此时更改列类型是不可能的,因为我不是 DBA,也不是有决定权的人。
我正在使用 XML 修改方法而不是 REPLACE,因为我不想沿着 XML 数据进行错误的替换。
还有其他类似的问题,但目前都没有答案
How to update XML in ntext column?
Inserting data to ntext xml column (Cannot call methods on ntext error)
代码:
DECLARE @NEW_EXAM_NAME NVARCHAR(10) = 'BCC'
DECLARE @CODE_DESC NVARCHAR(50)
SET @CODE_DESC = @CURRENT_EXAM_CODE + ' - ' + @NEW_EXAM_NAME
CREATE TABLE #temp_xml (xmlData XML)
INSERT INTO #temp_xml
SELECT CAST([data] AS XML)
FROM [dbo].[CodeSystemCodes_data]
WHERE [data] LIKE '%' + @CURRENT_EXAM_CODE + '%'
UPDATE #temp_xml
SET xmlData.modify('replace value of (/Utilities.CodeSystems.CodeSystemCodes/@Description)[1] with sql:variable("@NEW_EXAM_NAME")')
UPDATE #temp_xml
SET xmlData.modify('replace value of (/Utilities.CodeSystems.CodeSystemCodes/@CodeAndDescription)[1] with sql:variable("@CODE_DESC")')
SELECT * FROM #temp_xml
UPDATE [dbo].[CodeSystemCodes_data]
SET [data] = CAST(CAST((SELECT xmlData FROM #temp_xml) as nvarchar(max)) as ntext)
WHERE [data] LIKE '%' + @CURRENT_EXAM_CODE + '%'
DROP TABLE #temp_xml
不幸的是,当您的 XML 存储为文本时,您几乎无法执行类似于您所执行的操作。
如果你想摆脱对临时表的使用,你可以尝试这样的事情。您可以在 SSMS 中 运行 这个。
/* Base table mock-up */
DECLARE @Data TABLE ( [data] NTEXT, [id] INT IDENTITY (1,1) );
INSERT INTO @Data ( [data] ) VALUES
( '<root><values><val>Value 1</val><val>to_be_changed</val></values></root>' ),
( '<root><values><val>All is well here.</val><val>All is well here, too.</val></values></root>' ),
( '<root><values><val>Another value.</val><val>to_be_changed</val></values></root>' );
/* Find/Replace variables */
DECLARE
@find_value VARCHAR(50) = 'to_be_changed',
@replace_value VARCHAR(50) = 'Value 2';
/* Create a table variable to temporarily house the ntext data as xml so the XML may be modified */
DECLARE @Temp TABLE ( DataXml XML, id INT );
/* Insert [data] into the XML column */
INSERT INTO @Temp ( DataXml, [id] )
SELECT CAST ( [data] AS XML ), [id] FROM @Data WHERE [data] LIKE '%' + @find_value + '%';
/* Show the @Data resultset before modifying */
SELECT * FROM @Data;
/* The WHILE is to make sure every node that requires updating gets updated */
/* Modify each instance matching the @find_value criteria */
WHILE EXISTS ( SELECT * FROM @Temp WHERE DataXml.exist( '//root/values/val/text()[.=sql:variable("@find_value")]' ) = 1 )
UPDATE @Temp
SET
DataXml.modify ('
replace value of (/root/values/val/text()[.=sql:variable("@find_value")])[1]
with sql:variable("@replace_value")
');
/* Update the results back to the ntext column */
UPDATE @Data
SET
[data] = CAST ( t.DataXml AS NVARCHAR(MAX) )
FROM @Data d
INNER JOIN @Temp t
ON d.id = t.id;
/* Show the updated @Data resultset */
SELECT * FROM @Data;
@Data的初始select:
/* Show the @Data resultset before modifying */
SELECT * FROM @Data;
Returns
+---------------------------------------------------------------------------------------------+----+
| data | id |
+---------------------------------------------------------------------------------------------+----+
| <root><values><val>Value 1</val><val>to_be_changed</val></values></root> | 1 |
| <root><values><val>All is well here.</val><val>All is well here, too.</val></values></root> | 2 |
| <root><values><val>Another value.</val><val>to_be_changed</val></values></root> | 3 |
+---------------------------------------------------------------------------------------------+----+
@Data 的最终结果集:
/* Show the updated @Data resultset */
SELECT * FROM @Data;
Returns
+---------------------------------------------------------------------------------------------+----+
| data | id |
+---------------------------------------------------------------------------------------------+----+
| <root><values><val>Value 1</val><val>Value 2</val></values></root> | 1 |
| <root><values><val>All is well here.</val><val>All is well here, too.</val></values></root> | 2 |
| <root><values><val>Another value.</val><val>Value 2</val></values></root> | 3 |
+---------------------------------------------------------------------------------------------+----+
可能的替代方法:
也许在您的文本中添加一个简单的 REPLACE
。
UPDATE @Data
SET
[data] = REPLACE ( CAST ( [data] AS NVARCHAR(MAX) ), @find_value, @replace_value )
FROM @Data d
WHERE
d.[data] LIKE '%' + @find_value + '%';
更新:
我应该更清楚地说“我不想使用任何类型的中间表”
/* For-each find/replace instance found... */
WHILE EXISTS ( SELECT * FROM @Data WHERE CAST ( [data] AS XML ).exist( '//root/values/val/text()[.=sql:variable("@find_value")]' ) = 1 )
BEGIN
DECLARE @id INT, @xml XML;
SELECT TOP 1
@id = id,
@xml = CAST ( [data] AS XML )
FROM @Data
WHERE CAST ( [data] AS XML ).exist( '//root/values/val/text()[.=sql:variable("@find_value")]' ) = 1;
-- Modify the XML --
SET @xml.modify('
replace value of (/root/values/val/text()[.=sql:variable("@find_value")])[1]
with sql:variable("@replace_value")
');
-- Update the modified XML --
UPDATE @Data
SET
[data] = CAST ( @xml AS NVARCHAR(MAX) )
WHERE id = @id;
END
/* Show the updated resultset */
SELECT * FROM @Data ORDER BY id;
更新结果集:
+---------------------------------------------------------------------------------------------+----+
| data | id |
+---------------------------------------------------------------------------------------------+----+
| <root><values><val>Value 1</val><val>Value 2</val><val>Value 2</val></values></root> | 1 |
| <root><values><val>All is well here.</val><val>All is well here, too.</val></values></root> | 2 |
| <root><values><val>Another value.</val><val>Value 2</val></values></root> | 3 |
+---------------------------------------------------------------------------------------------+----+
OP更新
感谢您最后的解决方案,我最终这样做了,不需要 while 循环
DECLARE @CURRENT_EXAM_CODE NVARCHAR(10) = 'BXC_14B'
DECLARE @NEW_EXAM_NAME NVARCHAR(10) = 'BCC'
DECLARE @CODE_DESC NVARCHAR(50)
DECLARE @XML_DATA XML
-- convert existing NTEXT data into XML
SELECT @XML_DATA =
CAST([data] as xml)
FROM [dbo].[CodeSystemCodes_data]
WHERE [data] like '%' + @CURRENT_EXAM_CODE + '%'
-- update the xml data
SET @XML_DATA.modify('replace value of (/Utilities.CodeSystems.CodeSystemCodes/@Description)[1] with sql:variable("@NEW_EXAM_NAME")')
SET @CODE_DESC = @CURRENT_EXAM_CODE + ' - ' + @NEW_EXAM_NAME
SET @XML_DATA.modify('replace value of (/Utilities.CodeSystems.CodeSystemCodes/@CodeAndDescription)[1] with sql:variable("@CODE_DESC")')
-- convert xml data back to ntext type
UPDATE [dbo].[CodeSystemCodes_data]
SET
[data] = CAST(CAST(@XML_DATA as nvarchar(max)) as ntext)
WHERE [data] like '%' + @CURRENT_EXAM_CODE + '%'