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
Related
I'm trying to parse XML data in SQL Server. I have a XML column in a table, the XML stored in it can vary by type, but they all inherit from the same base type.
Row 1: has XML like so:
<Form>
<TaskType>1</TaskType>
--Other Properties ...
</Form>
Row 2: has XML like so:
<License>
<TaskType>2</TaskType>
--Other Properties ...
</License>
Normally I might parse XML with this T-SQL code snippet:
SELECT
xmlData.A.value('.', 'INT') AS Animal
FROM
#XMLToParse.nodes('License/TaskType') xmlData(A)
This doesn't work since in a view since I'm dependent on the name to find the node.
How can I always find the TaskType XML element in my XML content?
Please try the following solution.
XPath is using asterisk * as a wildcard.
http://www.tizag.com/xmlTutorial/xpathwildcard.php
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, xmldata XML);
INSERT #tbl (xmldata) VALUES
(N'<Form>
<TaskType>1</TaskType>
<TaskName>Clone</TaskName>
<!--Other XML elements-->
</Form>'),
(N'<License>
<TaskType>2</TaskType>
<TaskName>Copy</TaskName>
<!--Other XML elements-->
</License>');
-- DDL and sample data population, end
SELECT ID
, c.value('(TaskType/text())[1]', 'INT') AS TaskType
, c.value('(TaskName/text())[1]', 'VARCHAR(20)') AS TaskName
FROM #tbl
CROSS APPLY xmldata.nodes('/*') AS t(c);
Output
ID
TaskType
TaskName
1
1
Clone
2
2
Copy
Apparently you can just interate the nodes like so without being aware of their name:
SELECT xmlData.A.value('.', 'INT') AS Animal
FROM #XMLToParse.nodes('node()/TaskType') xmlData(A)
Hopefully this isn't too silly of a question. I've been trying to find an answer for a bit now.
Suppose I have a table like so:
MyTable:
Name NVARCHAR(25)
Data XML
How can I select the entire column value as XML?
declare #XmlVar xml = (select top 1 Data from MyTable)
Does not seem to allow manipulation of that xml later on.
declare #XmlVar xml = (select top 1 Data from MyTable FOR XML AUTO)
Seems to append additional nodes (<MyTable><Data>...)
It turns out I was not specifying the namespace required, and thus the Modify statement was not working.
So:
declare #XmlVar xml = (select top 1 Data from MyTable)
works fine.
#XmlVar.modify('declare default element namespace "MyNameSpaceUrl";
delete /RootNode[1]')
works when I specify the default element namespace as descibed in MyTable.Data.
Hope this saves someone else some time in the future.
Does anybody have any insight or encountered with this SQL Server behavior,
when blank value is converted into data type "char" or column which have "char" as data type - processed using For XML PATH, it returned XML result with "" special characters encoding for space,
When same blank value converted with varchar - it returns empty tag. My desired result is empty tag.
SELECT field=CONVERT(CHAR(10),'')
FOR XML PATH(''), ELEMENTS
--RESULT: <field> </field>
SELECT field=CONVERT(VARCHAR(10),'')
FOR XML PATH(''), ELEMENTS
--RESULT: <field></field>
The explanation in my view is when I'm using char it is inserting 10 spaces. And ASCII Hex20 or Decimal 32 - is a code for space.
It can be handled by using varchar instead of char as data type. But in my case I am reading field value from table defined in database:
--Example:
CREATE TABLE #temp(field CHAR(2))
INSERT INTO #temp
SELECT NULL
SELECT field=ISNULL(field,'')
FROM #temp
FOR XML PATH('')
DROP TABLE #temp
--RESULT: <field> </field>
--Desired Result:<field></field>
What is a most elegant way/or possibilities in SQL?
PS: I have a result set of 50 columns. I would like to handle this at database level without changing types. Real problem is my web service when encounter this character in XML throws a potentially dangerous value error.
Solution I used for desired result is, casting a whole result at once -
CREATE TABLE #temp(field CHAR(2))
INSERT INTO #temp
SELECT NULL
--Adding a cast to XML Result to convert it into varchar & then use replace.
SELECT REPLACE(CONVERT(VARCHAR(max),(SELECT field=ISNULL(field,'')
FROM #temp
FOR XML PATH(''))),' ','')
DROP TABLE #temp
would like to hear if there is any other suggestion?
You could do the following...up to you if you feel you need to TRIM or not;
CREATE TABLE #temp(field CHAR(2))
INSERT INTO #temp
SELECT NULL
SELECT field=COALESCE(NULLIF(RTRIM(LTRIM(field)), ''), '')
FROM #temp
FOR XML PATH('')
DROP TABLE #temp
I have a table in Sql server that stores Xml data in one of its columns.
The Xml column data looks like this:
<TestDef Weight="0" FailValue="2" ConceptID="-327">
<ToleranceDef ObjectType="SomeName" TargetValue="0"TargetRange="2" />
</TestDef>
I need to write a query that fetches out all the conceptId's from each rows Xml column.
Here it would be -327
I know I can cast the Xml column to a nvarchar(max) then use some reg exp to get the value but not sure how to use the regular expression
Here's an example using a table variable. It will be the same concept with an actual table:
Declare #XmlTable table (
Id Integer Identity,
XmlValue XML
)
Insert Into #XmlTable (XmlValue) values ('<TestDef Weight="0" FailValue="2" ConceptID="-327"><ToleranceDef ObjectType="SomeName" TargetValue="0" TargetRange="2" /></TestDef>')
Insert Into #XmlTable (XmlValue) values ('<TestDef Weight="0" FailValue="2" ConceptID="-325"><ToleranceDef ObjectType="SomeName" TargetValue="0" TargetRange="2" /></TestDef>')
select
Id,
XmlValue,
XmlValue.value('(/TestDef/#ConceptID)[1]', 'integer') as ConceptId
from
#XmlTable
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