SQL UNION FOR XML name output column - sql-server

I'm trying to generate an XML output from SQL and need to use a UNION statement and also name the output column.
I had this working before when I didn't need to use a UNION statement using:
select(
SELECT
[CompanyName],
[Address1],
[Address2],
[Address3],
[Town],
[County],
[Postcode],
[Tel],
[Fax],
[Email],
[LocMap]
FROM [UserAccs] FOR XML PATH ('AccountDetails'), root ('Root')
) as XmlOutput
Which named the output XML column as XmlOutput
I am now trying:
select(
SELECT
[CompanyName],
[Address1],
[Address2],
[Address3],
[Town],
[County],
[Postcode],
[Tel],
[Fax],
[Email],
[LocMap]
FROM [UserAccs]
UNION
SELECT
[CompanyName],
[Address1],
[Address2],
[Address3],
[Town],
[County],
[Postcode],
[Tel],
[Fax],
[Email],
[LocMap]
FROM [UserAppAccs]
FOR XML PATH ('AccountDetails'), root ('Root')
) as XmlOutput
But receive an error message, does anyone know a way around this?
The FOR XML clause is invalid in views, inline functions, derived tables, and subqueries when they contain a set operator. To work around, wrap the SELECT containing a set operator using derived table syntax and apply FOR XML on top of it.
Thanks
J.

Wrap your 2 selects on a single one like so:
select (
select id, name from (
select id, name
from xmltest
UNION
select id, name
from xmltest
) A
FOR XML PATH ('AccountDetails'), root ('Root')
) As XmlOutput

Related

Show multiple "parameter" xml nodes values into one row from Report Server Catalog table

I used the following SQL query to get the parameters from the ReportServer's Catalog table. In this query, I tried to use the following query to bring up some values, but it shows one value instead of the original number of parameters:
USE ReportServer
GO
SELECT Name,
CAST(Parameter as xml) [Parameter_XML],
CONCAT(Convert(XML,Parameter).value('(//Parameters/Parameter/Name)[1]','nvarchar(MAX)'), ', [', Convert(XML,Parameter).value('(//Parameters/Parameter/Type)[1]','nvarchar(MAX)'), ']') as [Parameter_List]
FROM Catalog
My expected end result would be like this:
Report Name
Parameter_XML
Parameter_List
My New Report with Parameters
XML goes here
Report_Name [DateTime], ReportDate [DateTime], etc...
How can I bring multiple parameter XML node values into one row?
There is a way to do this:
You simply read the nodes of each report, then use stuff for XML to create a comma seperated list.
USE ReportServer
GO
; with mycte as (
SELECT Name,
CAST(Parameter as xml) [Parameter_XML]
FROM Catalog
where Parameter is not null
)
, mycte2 as (
SELECT Name, T2.x.value('(Name)[1]', 'varchar(100)') as parameter_list
FROM mycte
CROSS APPLY [Parameter_XML].nodes('//Parameters/Parameter') as T2(x)
)
SELECT DISTINCT
Name as report_name,
STUFF(
(
SELECT ', ' + parameter_list
FROM mycte2 A1
WHERE A1.Name = A2.Name FOR XML PATH('')
), 1, 1, '') AS report_parameters
FROM mycte2 A2;
You can expand on this to get the types as well. But this should be a good starting point if not the whole solution!

How to write an SQL Select for XML including Union logic?

I have the following statement to get both dates into #xmlData
declare #xmlData OUTOUT
SET #xmlData = (SELECT #FileDate AS [FileDate] UNION SELECT #satDate AS [FileDate] FOR XML RAW, ELEMENTS)
Then I will insert it into the table:
DECLARE #ListOfDates TABLE (FileDate varchar(50))
INSERT #ListOfDates (FileDate)
SELECT Tbl.Col.value('FileDate[1]', 'varchar(50)')
FROM #xmlData.nodes('//row') Tbl(Col)
When executing my select logic, I'm getting an error saying:
The FOR XML and FOR JSON clauses are invalid in views, inline
functions, derived tables, and subqueries when they contain a set
operator. To work around, wrap the SELECT containing a set operator
using derived table or common table expression or view and apply FOR
XML or FOR JSON on top of it.
How to fix that?
I don't see why you're using XML at all here. But the error is telling you to push down that query into a derived table (subquery) or CTE, like this:
declare #xmlData xml
declare #filedate date = getdate()
declare #satdate date = '20140101'
SET #xmlData = (
select * from
( SELECT #FileDate AS [FileDate] UNION ALL SELECT #satDate AS [FileDate] ) d
FOR XML RAW, ELEMENTS, type
)
select #xmlData

How to retrieve data from XML column in sql server with no element name

I have XML like this in a column of a SQL Server table:
<Sales>
<customer>
<custID>6886903</custID>
<placeID>143144</placeID>UNKNOWN</customer>
</Sales>
How to retrieve UNKNOWN from above when it doesn't have any element name?
Actually, the UNKNOWN text belongs to the customer element.
DECLARE #data XML
SELECT #data = '<Sales>
<customer>
<custID>6886903</custID>
<placeID>143144</placeID>UNKNOWN</customer>
</Sales>'
SELECT p.value('(./custID)[1]' , 'int') AS custID,
p.value('(./placeID)[1]', 'int') AS placeID,
p.value('(./text())[1]' , 'varchar(max)') AS customerName
FROM #data.nodes('/Sales/customer') t(p)

Insert into select in SQL server

I am trying to convert data table to xml. It works fine. I want to store this converted xml in another table, So I tried using insert into select statement but it throws an error
The FOR XML clause is not allowed in a INSERT statement.
My query:
insert into table1 (column1)
select * from table2
for xml raw('product'),root('productDetails');
Updated :
This is tougher than i thought . what we have to do is
Save Xml in variable
then save Variable data to Table.(I think this can be simplified )
Code :
CREATE TABLE #MyXMLTable
(
xCol XML
) ;
DECLARE #testXML XML
SET #testXML = (
select * from "Product"
FOR XML RAW ('Product'), ROOT ('Products'));
select #testXML ;
INSERT INTO #MyXMLTable ( xCol )
SELECT #testXML;
SELECT * from #MyXMLTable
using-the-for-xml-clause-to-return-query-results-as-xml
insert-transact-sql

XPath in T-SQL query

I have two tables, XMLtable and filterTable.
I need all the XMLtable.ID values from XMLtable where the data in Col_X contains MyElement, the contents of which matches filterColumn in filterTable.
The XML for each row in Col_X may contain multiple MyElement's, and I want that ID in case ANY of those elements match ANY of the values in filterColumn.
The problem is that those columns are actually of varchar(max) datatype, and the table itself is huge (like 50GB huge). So this query needs to be as optimized as possible.
Here's an example for where I am now, which merely returns the row where the first matching element equals one of the ones I'm looking for. Due to a plethora of different error messages I can't seem to be able to change this to compare to all of the same named elements as I want to.
SELECT ID,
CAST(Col_X AS XML).value('(//*[local-name()=''MyElement''])', N'varchar(25)')
FROM XMLtable
...and then compare the results to filterTable. This already takes 5+ minutes.
What I'm trying to achieve is something like:
SELECT ID
FROM XMLtable
WHERE CAST(Col_X AS XML).query('(//*[local-name()=''MyElement''])')
IN (SELECT filterColumn FROM filterTable)
The only way I can currently achieve this is to use the LIKE operator, which takes like a thousand times longer.
Now, obviously it's not an option to start changing the datatypes of the columns or anything else. This is what I have to work with. :)
Try this:
SELECT
ID,
MyElementValue
FROM
(
SELECT ID, myE.value('(./text())[1]', N'VARCHAR(25)') AS 'MyElementValue'
FROM XMLTable
CROSS APPLY (SELECT CAST(Col_X AS XML)) as X(Col_X)
CROSS APPLY X.Col_X.nodes('(//*[local-name()="MyElement"])') as T2(myE)
) T1
WHERE MyElementValue IN (SELECT filterColumn FROM filterTable)
and this:
SELECT
ID,
MyElementValue
FROM
(
SELECT ID, myE.value('(./text())[1]', N'VARCHAR(25)') AS 'MyElementValue'
FROM XMLTable
CROSS APPLY (SELECT CAST(Col_X AS XML)) as X(Col_X)
CROSS APPLY X.Col_X.nodes('//MyElement') as T2(myE)
) T1
WHERE MyElementValue IN (SELECT filterColumn FROM filterTable)
Update
I think that you are experiencing what is described here Compute Scalars, Expressions and Execution Plan Performance. The cast to XML is deferred to each call to the value function. The test you should make is to change the datatype of Col_X to XML.
If that is not an option you could query the rows you need from XMLTable into a temporary table that has an XML column and then do the query above against the temporary table without the need to cast to XML.
CREATE TABLE #XMLTable
(
ID int,
Col_X xml
)
INSERT INTO #XMLTable(ID, Col_X)
SELECT ID, Col_X
FROM XMLTable
SELECT
ID,
MyElementValue
FROM
(
SELECT ID, myE.value('(./text())[1]', N'varchar(25)') AS 'MyElementValue'
FROM #XMLTable
CROSS APPLY Col_X.nodes('//MyElement') as T2(myE)
) T1
WHERE MyElementValue IN (SELECT filterColumn FROM filterTable)
DROP TABLE #XMLTable
You could try something like this. It does at least functionally do what you want, I believe. You'll have to explore its performance with your data set empirically.
SELECT ID
FROM
(
SELECT xt.ID, CAST(xt.Col_X AS XML) [content] FROM XMLTable AS xt
) AS src
INNER JOIN FilterTable AS f
ON f.filterColumn IN
(
SELECT
elt.value('.', 'varchar(25)')
FROM src.content.nodes('//MyElement') AS T(elt)
)
I finally got this working, and with far better performance than I expected. Below is the script that finally produced the correct result in 5 - 6 minutes.
SELECT ID, myE.value('.', N'VARCHAR(25)') AS 'MyElementValue'
FROM (SELECT ID, CAST(Col_X AS XML) AS Col_X
FROM XMLTable) T1
CROSS APPLY Col_X.nodes('(//*[local-name()=''MyElement''])' T2(myE)
WHERE myE.value('.', N'varchar(25)') IN (SELECT filterColumn FROM filterTable)
Thanks for the help tho people!

Resources