How to test if field is XML in xpath query? - sql-server

I query an image field to parse out the Lot number but I cannot be guaranteed that the image field will be XML. I am querying using embedded SQL. Not a stored proc.
How can I test if the field is XML and if not, get out gracefully?
i.e. NullIf (not XML) or equivalent.
DECLARE #x xml
SET #x = (SELECT [image]
FROM [QM].[dbo].[ticket]
where ticket_id = :ticketID)
SELECT #x.query('(/*:NewDataSet/*:tickets/*:lot/text())[1]')as LotNo

I actually run the query above. If it fails due to not being proper XML, I set the Lot No to '';

Related

How can i insert into MSSQL text Datatype field as xml

How can i insert into TSQL text field containing xml.
I can create custom fields in one of my Application which uses MSSQL as a back-end. When i create those custom fields, all go to a single field called fldxml in a table called MIITEM. I want to write Insert and update statement but i don't know how to insert record into fldxml field between <field></field>
<field1></field1> is custFld1( Custom Field1)
<field2></field2> is custFld2( Custom Field2)
<field3></field3> is custFld3( Custom Field3)
<field4></field4> is custFld4( Custom Field4)
here is how the data looks like in the field
<fields><field3>PFB652S6</field3><field1></field1><field2></field2><field4></field4></fields>
here is the Data Type
Indeed you should not use the TEXT datatype. For this purpose, use XML instead.
Regardless of the datatype, you can modify XML in TSQL by using the TSQL XML DML functionality. This makes it possible to write DML statements like INSERT, MODIFY, DELETE to modify XML documents.
Below is an example demonstrating this on your document:
-- First declare a variable of type XML
DECLARE #fields xml;
-- Here are the values we will be manipulating
DECLARE #nodeToReplace VARCHAR(MAX),#newValue VARCHAR(MAX)
SET #nodeToReplace = 'field3'
SET #newValue = 'PFB652S6'
-- Then fetch the value from the database. Insert the correct where clause
SELECT #fields=CAST(fldxml AS XML) FROM MIITEM WHERE .....
-- Now #fieds will contain your XML
SELECT #fields AS OldValue;
-- When the value of the node is empty, you have to insert the text node as follows.
SET #fields.modify('
insert text {sql:variable("#newValue")} as last into (/fields/*[ local-name()=sql:variable("#nodeToReplace") ])[1]
');
SELECT #fields AS NewInsertedValue;
-- When the value is present already, a slightly different syntax must be used to update it
SET #newValue = 'BLABLA'
SET #fields.modify('
replace value of (/fields/*[local-name()=sql:variable("#nodeToReplace")][1]/text())[1]
with sql:variable("#newValue")
');
SELECT #fields AS NewUpdatedValue;
Feel free to let me know if this sufficiently answers your questions. I could provide more specific help if needed.

Query XML data in SQL Server using replace in criteria

I have an XML column in my SQL Server 2008 table. What I'm trying to do is for a given parameter to my stored procedure strip out any spaces (using REPLACE) in the param and use this in the WHERE criteria but then using the XQuery exist clause also use the REPLACE method on the xml data:
-- Add the parameters for the stored procedure here
#PostCode varchar(20) = ''
AS
BEGIN
-- strip out any spaces from the post code param
SET #PostCode = REPLACE(#PostCode, ' ','')
SELECT TOP 1 *
FROM sd_LocalAuthorities
WHERE PostCodes.exist(N'REPLACE(/PostCodes/PostCode/text(), '' '','''')[. = sql:variable("#PostCode")]') = 1
END
I'm getting the error at XQuery sd_LocalAuthorities.PostCodes.exist()
There is no function '{http://www.w3.org/2004/07/xpath-functions}:REPLACE()
when running the procedure. Is there any alternatives to REPLACE() I can use to strip out spaces just for this WHERE criteria, I don't want to be modifying the table itself.
There is an XQuery function 'replace' but it's not available in TSQL where you want to use it. As an alternative approach you could pull the postcodes out of the XML and do the replace on native values. Something like this;
declare #sd_LocalAuthorities table (id int, postcodes xml)
declare #PostCode varchar(20); set #PostCode = 'BB11BB'
insert #sd_LocalAuthorities values (1, N'<PostCodes><PostCode>AA1 1AA</PostCode></PostCodes>')
insert #sd_LocalAuthorities values (2, N'<PostCodes><PostCode>BB1 1BB</PostCode></PostCodes>')
insert #sd_LocalAuthorities values (3, N'<PostCodes><PostCode>CC1 1CC</PostCode></PostCodes>')
select top 1
la.*
from
#sd_LocalAuthorities la
cross apply la.postcodes.nodes('/PostCodes/PostCode') as t(c)
where
replace(t.c.value('.', 'varchar(20)'), ' ', '') = #PostCode
This approach is more precise than converting the whole XML document/fragment to varchar because it only performs the replace on the postcode values. Depending on your circumstances an XML index may help performance.

Safe-casting text to XML

I have over a million rows in an SQLServer2005 database, with a text column that contains XML strings. I want to cast the text to the XML datatype in order to extract parts of the data.
The problem is there are some records that will throw errors when casting (ie. invalid XML). How can I ignore these errors so that all the valid XML is casted correctly and invalid XML is stored as null?
Once in a similar situation I added the XML column to the same table as the Text column. Then I used a RBAR process to attempt to copy the "XML" from the text column to the new XML column (not the fastest but commits single writes and this will be a one time thing, right?). This is assuming your table has a PK of an int data type.
declare #minid int, #maxid int;
select #minid=min(ID), #maxid=max(ID) from XMLTable;
while #minid <= #maxid
begin
begin try
update t
set XMLColumn = cast(TextColumn as XML)
from XMLTable t
where ID = #minid;
set #minid = #minid+1
end try
begin catch
print('XML transform failed on record ID:'+cast(#minid as varchar))
--advance to the next record
set #minid = #minid+1
end catch
end
I know this is SQL Server 2012+ functionality but since this question is the top Google result here it is:
SELECT
COALESCE(TRY_CONVERT(xml, '</bad xml>'), 'InvalidXML')
You can find the documentation here: TRY_CONVERT (Transact-SQL)

ms sql xml data type convert to text

in MS Sql there are data types that are not supported by delphi 7, the xml datatype is one example.
I wish to convert the XML datatype to Text datatype, so that i could handle it in delphi.
Is there a way to convert from xml to text?
A simple cast will suffice:
select cast(XMLCol as nvarchar(max)) as XMLCol
Or for non-unicode:
select cast(XMLCol as varchar(max)) as XMLCol
You can't convert explicitly to a 'text' data type.
I've added the as XMLCol to ensure that the converted data has the the same name as the column. You needn't have this, of course.
EDIT:
A few links. You are encouraged to use nvarchar(max) instead of text regardless. Microsoft have said they will be deprecating these types in future releases. nvarchar(max) ought to offer you 2GB:
http://www.petefreitag.com/item/734.cfm
http://www.teratrax.com/articles/varchar_max.html
http://msdn.microsoft.com/en-us/library/ms187752(v=SQL.90).aspx
SELECT CAST(YourXMLColumn as nvarchar(max))
FROM YourTable
I just tried the follwing solution and yes, you do need the as XMLCol
select cast(XMLCol as nvarchar(max)) as XMLCol

Best way to transfer an xml to SQL Server?

I have been hearing the podcast blog for a while, I hope I dont break this.
The question is this: I have to insert an xml to a database. This will be for already defined tables and fields. So what is the best way to accomplish this? So far I am leaning toward programatic. I have been seeing varios options, one is Data Transfer Objects (DTO), in the SQL Server there is the sp_xml_preparedocument that is used to get transfer XMLs to an object and throught code.
I am using CSharp and SQL Server 2005. The fields are not XML fields, they are the usual SQL datatypes.
In an attempt to try and help, we may need some clarification. Maybe by restating the problem you can let us know if this is what you're asking:
How can one import existing xml into a SQL 2005 database, without relying on the built-in xml type?
A fairly straight forward solution that you already mentioned is the sp_xml_preparedocument, combined with openxml.
Hopefully the following example illustrates the correct usage. For a more complete example checkout the MSDN docs on Using OPENXML.
declare #XmlDocumentHandle int
declare #XmlDocument nvarchar(1000)
set #XmlDocument = N'<ROOT>
<Customer>
<FirstName>Will</FirstName>
<LastName>Smith</LastName>
</Customer>
</ROOT>'
-- Create temp table to insert data into
create table #Customer
(
FirstName varchar(20),
LastName varchar(20)
)
-- Create an internal representation of the XML document.
exec sp_xml_preparedocument #XmlDocumentHandle output, #XmlDocument
-- Insert using openxml allows us to read the structure
insert into #Customer
select
FirstName = XmlFirstName,
LastName = XmlLastName
from openxml ( #XmlDocumentHandle, '/ROOT/Customer',2 )
with
(
XmlFirstName varchar(20) 'FirstName',
XmlLastName varchar(20) 'LastName'
)
where ( XmlFirstName = 'Will' and XmlLastName = 'Smith' )
-- Cleanup xml document
exec sp_xml_removedocument #XmlDocumentHandle
-- Show the data
select *
from #Customer
-- Drop tmp table
drop table #Customer
If you have an xml file and are using C#, then defining a stored procedure that does something like the above and then passing the entire xml file contents to the stored procedure as a string should give you a fairly straight forward way of importing xml into your existing table(s).
If your XML conforms to a particular XSD schema, you can look into using the "xsd.exe" command line tool to generate C# object classes that you can bind the XML to, and then form your insert statements using the properties of those objects: MSDN XSD Doc
Peruse this document and it will give you the options:
MSDN: XML Options in Microsoft SQL Server 2005
You may want to use XSLT to transfer your XML into SQL statements... ie
<xml type="user">
<data>1</data>
<data>2</data>
<xml>
Then the XSLT would look like
<xsl:template match="xml">
INSERT INTO <xsl:value-of select="#type" /> (data1, data2) VALUES (
'<xsl:value-of select="data[1]" />',
'<xsl:value-of select="data[2]" />');
</xsl:template>
The match statement most likely won't be the root node, but hopefully you get the idea. You may also need to wrap the non xsl:value-of parts in xsl:text to prevent extra characters from being dumped into the query. And you'd have to make sure the output of the XSLT was text. That said you could get a list of SQL statements that you could run through the DB. or you could use XSLT to output a T-SQL statement that you could load as a stored procedure.

Resources