Sql Xquery How to Replace text in Update Query - sql-server

Table is named as MasterTable
Columns
ID type BIGINT,
Name type VARCHAR(200) (stores xml type data for some reasons)
Name contains data structured as
<en-US>SomeEnglishText</en-US><it-IT>SomeItalicText</it-IT>
When I need to Update the Master Table then at that time I Need to cast the Varchar to xml then conditionally update / replace the value part of particular tag i.e either en-US / it-IT.
Also there are chances that No data/tags are there in Name column so I think at the time of Inserting data it would Insert empty tag elements in the table like <en-US></en-US><it-IT></it-IT>, so the update query must handle empty value in tag elements namely en-US/it-IT.
I am trying to do it like following update query.
DECLARE #Str VARCHAR(200)
SET #Str = 'Test Text'
UPDATE [MasterTable]
SET [Name] = cast([MasterTable].[Name] as xml).modify('replace value of (en-US/text())[1] with sql:variable("#Str")')
WHERE [ID]=18
I getting following error when running the query
Illegal use of xml data type method 'modify'. A non-mutator method is expected in this context.

You can not assign from a xml.modify. Modify works on the variable/column directly. You can also not use modify on a cast.
You can extract the name to a xml variable, modify the xml and then put it back to the table.
declare #str varchar(200) = 'Test'
declare #xml xml
select #xml = cast(Name as xml)
from MasterTable
where ID = 18
set #xml.modify('replace value of (en-US/text())[1] with sql:variable("#Str")')
update MasterTable
set Name = cast(#xml as varchar(200))
where ID = 18
If you need this to work over more than one row at a time you can use a table variable with columns id and name where data type for name is xml instead of the #xml variable.
declare #str varchar(200) = 'Test Text'
declare #T table (ID int, Name xml)
insert into #T
select ID, cast(Name as xml)
from MasterTable
where Name is not null
update #T
set Name.modify('replace value of (en-US/text())[1] with sql:variable("#Str")')
update MasterTable
set Name = cast(T.Name as varchar(200))
from #T as T
where MasterTable.ID = T.ID

Related

Modify XML in SQL field stored as Varbinary

My XML is stored as varbinary in a field.
SELECT cast (inboxXml as xml) FROM globalDB.Inbox WHERE inboxCId = '207435-N'
I would like to update one attribute (below). However the error is "Cannot call methods on varbinary(max)." I tried different ways to cast it, but I cannot find it.
thank you,
;WITH XMLNAMESPACES(DEFAULT 'http://www.w3.org/2001/XMLSchema')
UPDATE globalDB.Inbox
SET inboxXml.modify('replace value of (//ReceiveDeliveryHeader/DocumentID/ID/#accountingEntity[.="ABC"])[1] with "ZZZ"')
WHERE inboxCId = '207435-N'
The first question is: Why are you storing your XML within a VARBINARY column?
This is slow, clumsy and erronous...
The second thing is: .modify() will work against a real native XML only. Neither inboxXml.modify() nor CAST(inboxXml AS XML).modify() will work...
This is one more reason to change your column's type to XML...
Try this:
DECLARE #tbl TABLE(ID INT IDENTITY,YourXml VARBINARY(MAX));
DECLARE #SomeXML XML='<root><someNode someAttr="test">content</someNode></root>';
INSERT INTO #tbl VALUES(CAST(#SomeXML AS VARBINARY(MAX)));
--this works
SELECT ID
,YourXml
,CAST(YourXml AS XML)
FROM #tbl
WHERE ID=1;
--but this is not allowed
UPDATE #tbl SET CAST(YourXml AS XML).modify('replace value of (/root/someNode/#someAttr)[1] with "blah"')
WHERE ID=1
--What you can do:
DECLARE #intermediateXML XML= (SELECT CAST(YourXml AS XML) FROM #tbl WHERE ID=1);
SET #intermediateXML.modify('replace value of (/root/someNode/#someAttr)[1] with "blah"');
UPDATE #tbl SET YourXml=CAST(#intermediateXML AS VARBINARY(MAX)) WHERE ID=1;
--voila!
SELECT ID
,YourXml
,CAST(YourXml AS XML)
FROM #tbl
WHERE ID=1;

How to INSERT INTO table column with string/variable

This is the data I have pulled from powershell and inserted it into a #temptable:
Name : SULESRKMA
Location : Leisure Services - Technology Services
Shared : False
ShareName :
JobCountSinceLastReset : 0
PrinterState : 131072
Status : Degraded
Network : False
I'm while looping through the data and have stripped the values from the identifiers. I'd like to use these identifiers to insert the values into a table with identical Column names to the identifiers. So for example, I have a variable called #identifier = "Name" and a temp table #printers with a column name of Name. I'd like to do something like:
SELECT --select statement
INSERT INTO #printers(#identifier)
But This doesn't seem to work, unsurprisingly. Is there a way to accomplish this? (The #identifier variable will be changing to the other identifiers in the data throughout the course of the while loop.)
Any alternate suggestions that don't even involve using this sort of method are welcome. My ultimate goal is just to get this data as a row into a table.
(I'm currently using Microsoft SQL Server Management Studio if that matters)
First, it's unlikely you need to loop over anything in this situation. Think set based operations when you think about SQL.
INSERT INTO #temptable (Column1Name, Column2Name, Column3Name)
VALUES (#identifer, #anotherIdentifier, #someOtherIdentifier)
--optional clauses
WHERE Column1Name = 'some value' OR Column1Name = #someIdentifier
Or you can SELECT INTO
SELECT
#identifier,
#anotherIdentifer,
#someOtherIdentifier
INTO #temptable
It's important that you have a value in your SELECT INTO for each column in the table which you are trying to add the data to. So, for example, if there were 4 columns in #temptable and you only had 3 values to insert (columns 1, 2 , and 3) then you'd need to NULL column 4 or set it statically.
SELECT
#identifier,
#anotherIdentifer,
#someOtherIdentifier,
NULL
INTO #temptable
--or
SELECT
#identifier,
#anotherIdentifer,
#someOtherIdentifier,
'static value'
INTO #temptable
EDIT
If you want to use a varible to speciy the column that you want to insert into, you have to use dynamic sql. Here is an example:
if object_id ('tempdb..#tempTable') is not null drop table #tempTable
create table #tempTable (Column1Name int, Column2Name int, Column3Name int)
declare #columnName varchar(64) = 'Column1Name'
declare #sql varchar(max)
set #sql =
'insert into #tempTable (' + #columnName + ')
select 1'
exec(#sql)
select * from #tempTable

How can I update multiple XML fields with MSSQL?

Table Name : TBL_CLIENTS
Table Field : XMLDATA
<REPORT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" DESCRIPTION="TestClient" FILENUM="1234">
<!--<REPORT DESCRIPTION="TestClient" FILENUM="1234">-->
<TRACKING>
<FIRSTNAME>Bobby</FIRSTNAME>
<LASTNAME>Butcher</LASTNAME>
</TRACKING>
</REPORT>
I want to change both the FIRSTNAME and LASTNAME. Is there anyway I can do it in a single query? The only way I can figure it out is using two queries.
UPDATE TBL_CLIENTS
SET [XMLDATA].modify('replace value of (/REPORT/TRACKING/FIRSTNAME/text()) [1] with ("Franny")')
WHERE ORDERID = 5
and
UPDATE TBL_CLIENTS
SET [XMLDATA].modify('replace value of (/REPORT/TRACKING/LASTNAME/text())[1] with ("Farmer")')
WHERE ORDERID = 5
It's not possible - per MSDN, replace has to work on a single instance of an XML node - but you could avoid doing two UPDATEs on the table this way:
DECLARE #doc xml = '<REPORT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" DESCRIPTION="TestClient" FILENUM="1234">
<!--<REPORT DESCRIPTION="TestClient" FILENUM="1234">-->
<TRACKING>
<FIRSTNAME>Bobby</FIRSTNAME>
<LASTNAME>Butcher</LASTNAME>
</TRACKING>
</REPORT>';
DECLARE #t table (xmldata xml);
insert #t (xmldata) values (#doc);
-- grab the XML data from the table for manipulation...
DECLARE #xmlData xml;
SELECT #xmlData = xmldata FROM #t;
set #xmlData.modify('replace value of (/REPORT/TRACKING/FIRSTNAME/text()) [1] with ("Franny")')
set #xmlData.modify('replace value of (/REPORT/TRACKING/LASTNAME/text()) [1] with ("Farmer")')
-- now we only need to do one update on the table itself.
UPDATE #t
SET [XMLDATA] = #xmlData
SELECT * FROM #t;
I know this isn't exactly what you were asking for, but it should result in less locking time and better performance on the table - if that's something you're aiming for.

Passing parameter to a SQL Server stored procedure

I am trying to write a SQL query and that works, but the stored procedure is not working when I try with parameters.
Example :
select *
from Table1
where Name = 'BEST People' // this works
// this does not show any rows
declare #Name nvarchar(128)
set #Name= 'BEST People'
select *
from Table1
where Name = #Name
Even when I try with a stored procedure, it does not work.
Depending on your column collation String Comparison Work
Specify Your Question Like This
Here's how you would check your column collation:
DECLARE #TableId INT
SELECT #TableId=id FROM sys.sysobjects
WHERE xtype='U' AND name='Table1'; --Your table name here
SELECT name, collation_name FROM sys.columns
WHERE object_id=#TableId AND name=N'Name'; --Your column name here
View Collation Information
You need to cast the string to NVARCHAR:
declare #Name nvarchar(128)
set #Name= N'BEST People'
select * from Table1 where Name = #Name
Without the N it will be a VARCHAR

Update XML Node with Conversion in SQL Server 2005

I have a column that contains XML data, but is TEXT type and not XML type. (I have to leave it like this for another reason).
Basically i need to cast it to NText first and then XML. The only problem is my current format that works for selecting the Node value doesnt work to update it.
Error Message: Incorrect syntax near the keyword 'AS'.
UPDATE tbl_Module_RequestForms_Items
SET CAST(CAST(TicorOregon..tbl_Module_RequestForms_Items.XML AS NTEXT) AS XML).value('(//Record/Submitted)[1]', 'NVARCHAR(max)') = 'True'
WHERE CAST(CAST(TicorOregon..tbl_Module_RequestForms_Items.XML AS NTEXT) AS XML).value('(//Record/Submitted)[1]', 'NVARCHAR(max)') <> 'True'
XML Data:
<Record>
<Submitted>False</Submitted>
</Record>
There might be valid reason to store XML in a [n]varchar(max). If you want to only store the XML it is perfectly OK but if you want to modify parts of the XML using TSQL or if you need to query the XML for values or use node/attribute values in a where clause you should switch to XML where you can benefit from indexes on the data and skip the type conversions. Since text is deprecated you should at least consider to switch data type to [n]varchar(max)
If you had your data in a XML column you would use XML DML to modify the XML. In your case you would use replace value of like this.
update tbl_Module_RequestForms_Items
set XMLData.modify('replace value of (/Record/Submitted/text())[1] with "True"')
where XMLData.value('(/Record/Submitted)[1]', 'bit') = 0
Without the XML data type that is not possible so you have to extract the entire XML document, modify it and then update the table with the modified XML document.
You can of course do that using some kind of client development tool but it is also possible in TSQL.
Declare a table variable with the primary key from tbl_Module_RequestForms_Items and the XMLData column but as data type XML.
Copy the rows from tbl_Module_RequestForms_Items to the table variable that should be updated.
Update the XML using replace value of.
Apply the changes back to tbl_Module_RequestForms_Items.
Something like this where I assume that ID is the primary key for tbl_Module_RequestForms_Items and that your XML data is in column XMLData:
declare #T table
(
ID int primary key,
XMLData xml
)
insert into #T
select M.ID,
M.XMLData
from tbl_Module_RequestForms_Items as M
where cast(cast(XMLData as nvarchar(max)) as xml).value('(/Record/Submitted)[1]', 'bit') = 0
update #T
set XMLData.modify('replace value of (/Record/Submitted/text())[1] with "True"')
update M
set XMLData = cast(T.XMLData as nvarchar(max))
from tbl_Module_RequestForms_Items as M
inner join #T as T
on M.ID = T.ID

Resources