select xml rows without column header in SQL Server FOR XML - sql-server

In SQL Server 2008 R2, I have a table with rows of valid XML nodes (one column, xml type) that looks like this:
create table #t (x xml not null);
insert into #t
values ('<service><value1>stuff</value1><value2>more stuff</value2></service>')
, ('<service><value1>I am a different row</value1><value2>more stuff</value2></service>');
I would like to select these into one XML blob:
<services>
<service>. . .</service>
<service>. . .</service>
</services>
I am using FOR XML PATH to try this, but it embeds the column header "x" as a node around the "service" nodes.
select x
from #t
for XML PATH(''), ROOT('services')
This produces:
<services>
<x><service>. . .</service></x>
<x><service>. . .</service></x>
</services>
How can I get rid of the "x" node?
I tried select x as "" and select x as "." but these are reserved words, and the query errors out.

How about this?
select x.query('*')
from #t
for xml path(''), root('services')

Related

SQL Result to XML (Specific Layout)

I have a table in SQL that contains a list of settings for an application per serverID
I want write a SQL statement that produce a specific XML layout.
The basic SQL statement to retrieve this data:
SELECT SettingName, SettingValue
FROM dbo.ServerSettings
WHERE ServerID = #ServerID
I just need to know the correct FOR XML options.
I want to get back a result like the following. Basically using the value of the SettingName field to be the name of the node.
<ROOT>
<COSTRECOVERYSYSTEM_CONNECTION_STRING></COSTRECOVERYSYSTEM_CONNECTION_STRING>
<COSTRECOVERYSYSTEM_EXTRACT_INTERVAL>60</COSTRECOVERYSYSTEM_EXTRACT_INTERVAL>
<COSTRECOVERYSYSTEM_FILE_DATESTAMP>yyyyMMdd</COSTRECOVERYSYSTEM_FILE_DATESTAMP>
<COSTRECOVERYSYSTEM_FILE_EXTENSION>txt</COSTRECOVERYSYSTEM_FILE_EXTENSION>
<COSTRECOVERYSYSTEM_FILE_NAME>txt</COSTRECOVERYSYSTEM_FILE_NAME>
<COSTRECOVERYSYSTEM_FILE_PATH>txt</COSTRECOVERYSYSTEM_FILE_PATH>
</ROOT>
As in any other query you cannot use a column's value as the output column name. This would need some dynamically created statement and EXEC() for its execution.
But you might do something along this:
DECLARE #tbl TABLE(SettingName VARCHAR(100),SettingValue VARCHAR(100));
INSERT INTO #tbl VALUES ('Setting1','1'),('Setting2','2'),('ForbiddenValue','Huh! What about & and <?');
SELECT CAST((
SELECT '<' + UPPER(t.SettingName) + '>' +
--this embedded FOR XML will implicitly do the escaping for you
(SELECT t.SettingValue AS [*] FOR XML PATH('')) +
'</' + UPPER(t.SettingName) + '>'
FROM #tbl t
FOR XML PATH(''),TYPE
).value('.','nvarchar(max)') AS XML)
FOR XML PATH('ROOT');
In general I would never create XML with string methods. There are so many possible draw backs and traps. But in this case it might be the best choice.
Hint: Be sure, that the setting names are valid XML element names. There are some XML element naming rules
You can see these links for more information:
1. https://learn.microsoft.com/en-us/sql/relational-databases/xml/for-xml-sql-server?view=sql-server-2017
2. https://www.red-gate.com/simple-talk/sql/learn-sql-server/using-the-for-xml-clause-to-return-query-results-as-xml/

Performing sqlcmd for query containing FOR XML and writing output in XML path. Generated XML format is damaged and some text are removed

I have SQL query for XML like the following (SQL Server 2012):
Use MedStreaming
SELECT distinct 1 as Tag,
NULL as Parent,
NULL AS [ExamTypes!1],
NULL as [ExamType!2!ExamTypeID],
NULL as [Template!3!ShortString],
NULL as [Template!3!Order]
UNION ALL
SELECT distinct 2 as Tag,
1 as Parent,
NULL,
Temp_Type.ExamTypeId as [ExamType!2!ExamTypeID],
NULL as [Template!3!ShortString],
NULL as [Template!3!Order]
FROM LayoutSectionTemplate_ExamType AS Temp_Type
INNER JOIN LayoutSection_Template as temp
ON Temp_Type.TemplateId = temp.TemplateId
UNION ALL
SELECT 3 as Tag,
2 as Parent,
NULL,
Temp_Type.ExamTypeId,
temp.ShortString,
Temp_Type.[Order]
FROM LayoutSectionTemplate_ExamType AS Temp_Type
INNER JOIN LayoutSection_Template as temp
ON Temp_Type.TemplateId = temp.TemplateId
ORDER BY [ExamType!2!ExamTypeID],[Template!3!Order]
FOR XML EXPLICIT
I try to call it and write the XML result in an XML file using the following command:
sqlcmd -i "%~dp0\MedStreaming.Util\Scripts\GetExamTypes-TemplatesRelations.sql" -o "C:\temp\examTypes-reportsTemplates.xml"
But the file result XML format is not correct, and some texts are removed.
I tried to put "XML ON" on the first of the query, but it doesn't work (it gives me syntax error).
Any help ?
This is an annoying limitation of SQLCMD interface (same for Invoke-SqlCmd the Powershell module) - you have to put the XML or JSON output into NVARCHAR(MAX) or XML datatype so that SQLCMD can handle the output properly. There is a 2MB rowsize threshold for SQLCMD output whereafter it starts chunking the output data into additional DataRows.
Note: You should also set MaxCharLength if the data exceeds 4K characters in size.
SQLCMD XML Output
DECLARE #XML as XML
SET #XML= (select Name from TestXML For XML path ('')
SQLCMD JSON Output
DECLARE #json NVARCHAR(MAX)
SELECT #json = (select * from mytable for json auto)
select * from openjson(#json)
Another option is to use bcp utility which outputs directly to disk for larger data dumps.

Extract XML Node data SQL Query

I am trying to extract XML node from SQL query. I have XML report specification in one of the column of SQL table.
I want to extract sqlText node from the XML using SQL query.
I have uploaded the xml to dropbox:
https://www.dropbox.com/sh/28xu7ifu78h6gm0/AACQS24NEjPFO0GXEI9vLuefa?dl=0
Any help would be greatly appreciated.
If you are using xml document
declare #xml xml ='<report ....</report>'
select #xml.value('(/report/queries/query/source/sqlQuery/sqlText)[1]', 'varchar(100)') as [SqlText]
Assuming that the XML data is stored in XML typed column named myXmlColumn in SQL table named myTable, you can specify the default namespace for the XPath using ;WITH XMLNAMESPACES(), for example :
;WITH XMLNAMESPACES(default 'http://developer.cognos.com/schemas/report/8.0/')
select myTable.myXmlColumn.value('(/report/queries/query/source/sqlQuery/sqlText)[1]'
, 'varchar(max)') as sqlText
If there are more than one sqlQuery node, following SQL XML query can be used
SELECT
[Query].value('.','varchar(100)') AS QueryText
FROM #xml.nodes('/report/queries/query/source/sqlQuery/sqlText') Queries([Query])

inline schema is not supported with for xml path xmlschema

I would like to write a stored procedure as below in SQL Server.
CREATE PROC [dbo].[Employee_delete]
AS
BEGIN
SELECT *
FROM #employee
FOR XML PATH(''), root ('EmployeeDelete'),xmlschema
END
But I'm getting the error--> 'inline schema is not supported with for xml path xmlschema'. May I know, how can I achieve XMLSchema with code "FOR XML PATH(''), root ('EmployeeDelete'),xmlschema"
To auto generate schemas in biztalk , I have to use word "xmlSchema"
Thanks in advance
If you are using BizTalk-2010 you should be using the WCF-SQL adapter for which you don't need to select as FOR XML to be able to generate schemas.
Try...
FOR XML AUTO,ROOT('EmployeeDelete'), TYPE, ELEMENTS XSINIL, XMLSCHEMA

Querying XML data in sql server 2005

i got a snippet which show how to query xml data in sql server but few area still not clear to me.
DECLARE #xml XML
SET #xml = '<root>
<row>one</row>
<row>two</row>
<row>three</row>
</root>'
CREATE TABLE #Fields(Field varchar(MAX))
INSERT INTO #Fields
SELECT
x.y.value('text()[1]', 'varchar(5)')
FROM #xml.nodes('root/row') x(y)
SELECT * FROM #Fields
DROP TABLE #Fields
what is x.y i just do not understand and also what kind of syntax is it 'text()[1]', 'varchar(5)'
if text() is in-built function then does it work for any data type ?
please help me to visualize what x.y ?? thanks
The .nodes() call converts your XML into a list of XML fragments - and a "list" in SQL Server always is a table - so this is really a table alias (x) and a column alias (y) for an internally constructed tables of XML fragments (one "row" per match for .nodes())
If you would be using .nodes('/root)` then you'd get an "pseudo table" with these rows:
Table x
y
----------------
<row>one</row>
<row>two</row>
<row>three</row>
Since you're using .nodes('/root/row') instead, you're really getting just the values of those <row> elements:
Table x
y
----------------
one
two
three
The .value() now takes one of those XML fragments and returns something from it. It could be the name of a sub-element - but text() (yes, a built-in XQuery function) just converts the whole XML fragment into a textual representation. The second parameter of the .value() call just defines what that value should be treated as - what datatype.

Resources