Combine 2 XML Output Statements into one XML file - sql

I've been working on outputting from SQL to XML and have finally come up with 2 queries that work fabulously for what I need with one problem. I did these independently as I am a novice with XML and now I need to combine them into one file for output. What I have is pretty complicated using dynamic SQL so I'm just going to post the dynamic part and exclude all of the variable and un-pivoting stuff I'm doing at the beginning. If I could just get result set 1 to be at the top and result set 2 just below it would suffice. I would like a wrapper tag (not sure if that's the term) as the very first and very last lines in this file. I'm not sure if anyone can tell me what I'm doing wrong just by looking at the dynamic code but I thought it would be worth a try. As I said, both of these work great but produce 2 separate files. Thanks in advance!
EXEC ('
SELECT
(SELECT GETDATE() AS STARTDATE,
GETDATE() AS ENDDATE
FOR XML PATH(''RECDATE''),ELEMENTS, TYPE),
(SELECT COUNT(*) AS SURVEY_COUNT
FROM PM_TEMP.dbo.tmpKansasCancerCenterExtract FOR XML PATH(''''), ELEMENTS, TYPE),
(SELECT ''PEPM'' as SERVICE,
DataCol as VARNAME,
Question as QUESTION_TEXT,
AnswerValue as ANSWER_TEXT
from PM_TEMP.dbo.tmpKansasCancerCenterCodeSheetExtract FOR XML PATH(''QUESTION''), ROOT(''QUESTION_MAP''), ELEMENTS, TYPE)
FOR XML PATH(''HEADER'')
SELECT PATID,CLIENTID,SERVICE,PATVISITDT,DATE,
(
SELECT VarName,Value
FROM PM_TEMP.dbo.tmpKansasCancerCenterExtract_AnalysisPivot P
INNER JOIN PM_TEMP.dbo.tmpKansasCancerCenterExtract E ON E.PatVisitID = P.PatVisitID
FOR XML PATH(''Response''), TYPE, ROOT(''Analysis'')
),
(
SELECT VarName,Value
FROM PM_TEMP.dbo.tmpKansasCancerCenterExtract_DemoPivot P
INNER JOIN PM_TEMP.dbo.tmpKansasCancerCenterExtract E ON E.PatVisitID = P.PatVisitID
FOR XML PATH(''Response''), TYPE, ROOT(''Demographics'')
)
FROM PM_TEMP.dbo.tmpKansasCancerCenterExtract
FOR XML PATH(''PatientLevelData''),TYPE, ROOT(''PatientLevelData'')
')

Related

SQL - Cannot find either column "c" or user-defined function or aggregate "c" or the name is ambiguos

I'm not really good in SQL and I did some searching and couldn't really figured it out how to use STUFF. I mean it looks simple but when I use it, there's always an error.
Anyway, here is the portion of my code and I just want to combine 2 printer of the rows with the same computer name pulled from database, honestly I'm not even sure if I'm doing it right but please do correct me if I'm wrong. Really need the professionals to guide me and do let me know if the information is not sufficient. Thanks in advance.
Update:
Added more code, and I didn't mention clearly, my query is pulling different data from multiple tables. It may be a bit messy but it got what I wanted, my problem is combining the printer result.
SELECT DISTINCT sc.ComputerName AS 'Computer name',
*
*
*
ISNULL(c.PrinterName <-- error on this c.printername
(
STUFF
((
SELECT
'; ' + c.PrinterName
FROM PrinterList AS c
WHERE c.ComputerName = sc.ComputerName
FOR XML PATH(''), TYPE).value('.','nvarchar(max)'), 1, 2,'')), '') AS 'Printer'
FROM Computer sc
Full Join PCInfo AS a
ON a.ComputerName = sc.ComputerName
Full Join DriverList AS b
ON b.ComputerName = sc.ComputerName
Full Join PrinterList AS c
ON c.ComputerName = sc.ComputerName
WHERE RTRIM(LTRIM(REPLACE(lower(sc.ComputerName), ' ',''))) like '%example%'
The c alias is only available in the namespace of the subquery, but you do not reference it from there.
I would expect something like this:
SELECT c.PrinterName,
STUFF( (SELECT '; ' + c.PrinterName
FROM PrinterList AS c
WHERE c.ComputerName = sc.ComputerName
FOR XML PATH(''), TYPE
).value('.', 'nvarchar(max)'
), 1, 2, '')
) as printers
FROM computer c ;
There is no need for the join in the outer query. I also don't see why an outer join would be desired.

SQL to XML not able to create proper XMLNAMESPACE due to quotation marks (I think)

I have the following query:
WITH XMLNAMESPACES ('CommonImport StudentRecordCount="1"
xsi:schemaLocation="http://collegeboard.org/CommonImport CommonImport.xsd"
xmlns="http://collegeboard.org/CommonImport"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' AS CommonImport)
SELECT B.award_year_token AS [StudentID/AwardYearToken]
,A.student_ssn AS [StudentID/SSN]
,A.last_name AS [StudentName/LastName]
,A.first_name AS [StudentName/FirstName]
,A.alternate_id AS [StudentName/AlternateID]
,'2807' AS [CustomStrings/CustomString/FieldID]
,C.processed_status AS [CustomStrings/CustomString/Value]
,'2506' AS [CustomDates/CustomDate/FieldID]
,CAST (C.date_processed AS DATE) AS [CustomDates/CustomDate/Value]
FROM [dbo].[student] A INNER JOIN [stu_award_year] B ON A.[student_token] = B.[student_token]
LEFT OUTER JOIN [dbo].[isir_convert_data] C ON A.[student_ssn] = C.[ssn] AND B.award_year_token = C.award_year_token
--LEFT OUTER JOIN [user_string] E ON B.[stu_award_year_token] = E.[stu_award_year_token]
--WHERE B.AWARD_YEAR_TOKEN = 2018 --For 18-19 year.
WHERE B.AWARD_YEAR_TOKEN = 2017 --For 17-18 year.
AND C.processed_status ='B'
AND C.date_processed = (SELECT MAX (X.date_processed)
FROM isir_convert_data X
WHERE C.ssn = X.ssn)
FOR XML PATH('Student'), ROOT('CommonImport')
The output is unusable due to the mishandling of the quotation marks. It looks like the following:
<CommonImport xmlns:CommonImport="CommonImport StudentRecordCount="1" xsi:schemaLocation="http://collegeboard.org/CommonImport CommonImport.xsd" xmlns="http://collegeboard.org/CommonImport" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"">
I am generating this via SQL Server. Can you offer any advice on how to properly create the XML Tag? And if I'm not properly using the XMLNAMESPACE function, please let me know. Thank you for considering.
You must distinguish between
the declaration of a namespace and
the usage of a namespace
It seems to me, that StudentRecordCount should be an attribute in the <CommonImport> node, same with schemaLocation. The second attribute is living within the xmlns:xsi-namespace.
You did not state the expected output, but my magic crystal ball showed me, that you might need this:
WITH XMLNAMESPACES (DEFAULT 'http://collegeboard.org/CommonImport'
,'http://www.w3.org/2001/XMLSchema-instance' AS xsi)
SELECT 1 AS [#StudentRecordCount]
,'http://collegeboard.org/CommonImport CommonImport.xsd' AS [#xsi:schemaLocation]
,'SomeOtherData' AS [Student/SomeElement]
FOR XML PATH('CommonImport');
the result
<CommonImport xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://collegeboard.org/CommonImport"
StudentRecordCount="1"
xsi:schemaLocation="http://collegeboard.org/CommonImport CommonImport.xsd">
<Student>
<SomeElement>SomeOtherData</SomeElement>
</Student>
</CommonImport>
If this does not help enough, please read about how to create a MCVE and provide sample data and expected output.
UPDATE 1
This is - roughly - what you need, but the namespaces are repeated. This is a known and annoying issue. Not wrong, the result is perfectly okay, but bloated.
WITH XMLNAMESPACES (DEFAULT 'http://collegeboard.org/CommonImport'
,'http://www.w3.org/2001/XMLSchema-instance' AS xsi)
,cte AS
(
SELECT object_id,name FROM sys.objects
)
SELECT COUNT(*) AS [#RecordCount]
,'http://collegeboard.org/CommonImport CommonImport.xsd' AS [#xsi:schemaLocation]
,(
SELECT *
FROM cte
FOR XML PATH('Object'),TYPE
)
FROM cte
FOR XML PATH('CommonImport');
UPDATE 2
An ugly workaround
WITH cte AS
(
SELECT object_id,name FROM sys.objects
)
SELECT
CAST(REPLACE(REPLACE(REPLACE(CAST(
(
SELECT COUNT(*) AS [#RecordCount]
,'http://collegeboard.org/CommonImport CommonImport.xsd' AS [#xsi_schemaLocation] --<-- "xsi:" is replaced with "xsi_"
,'http://collegeboard.org/CommonImport' AS [#_xmlns_] --<-- "xmlns" is not allowed
,'http://www.w3.org/2001/XMLSchema-instance' AS [#_xmlns_xsi] --<-- Same with "xmlns:xsi"
,(
SELECT *
FROM cte
FOR XML PATH('Object'),TYPE
)
FROM cte
FOR XML PATH('CommonImport'),TYPE) AS nvarchar(MAX)),'xsi_','xsi:'),'_xmlns_',' xmlns'),'xmlnsxsi','xmlns:xsi') AS XML);
Alternatively you might create the whole thing without namespaces at all and add the namespace declaration with string methods at the end.

Querying XML colum for values

I have a SQL Server table with an XML column, and it contains data something like this:
<Query>
<QueryGroup>
<QueryRule>
<Attribute>Integration</Attribute>
<RuleOperator>8</RuleOperator>
<Value />
<Grouping>OrOperator</Grouping>
</QueryRule>
<QueryRule>
<Attribute>Integration</Attribute>
<RuleOperator>5</RuleOperator>
<Value>None</Value>
<Grouping>AndOperator</Grouping>
</QueryRule>
</QueryGroup>
</Query>
Each QueryRule will only have one Attribute, but each QueryGroup can have many QueryRules. Each Query can also have many QueryGroups.
I need to be able to pull all records that have one or more QueryRule with a certain attribute and value.
SELECT *
FROM QueryBuilderQueries
WHERE [the xml contains any value=X where the attribute is either Y or Z]
I've worked out how to check a specific QueryRule, but not "any".
SELECT
Query
FROM
QueryBuilderQueries
WHERE
Query.value('(/Query/QueryGroup/QueryRule/Value)[1]', 'varchar(max)') like 'UserToFind'
AND Query.value('(/Query/QueryGroup/QueryRule/Attribute)[1]', 'varchar(max)') in ('FirstName', 'LastName')
You can use two exist(). One to check the value and one to check Attribute.
select Q.Query
from dbo.QueryBuilderQueries as Q
where Q.Query.exist('/Query/QueryGroup/QueryRule/Value/text()[. = "UserToFind"]') = 1 and
Q.Query.exist('/Query/QueryGroup/QueryRule/Attribute/text()[. = ("FirstName", "LastName")]') = 1
If you really want the like equivalence when you search for a Value you can use contains().
select Q.Query
from dbo.QueryBuilderQueries as Q
where Q.Query.exist('/Query/QueryGroup/QueryRule/Value/text()[contains(., "UserToFind")]') = 1 and
Q.Query.exist('/Query/QueryGroup/QueryRule/Attribute/text()[. = ("FirstName", "LastName")]') = 1
According to http://technet.microsoft.com/pl-pl/library/ms178030%28v=sql.110%29.aspx
"The XQuery must return at most one value"
If you are quite certain that for example your XML has let's say maximum 10 QueryRules you could maybe use WHILE to loop everything while droping your results into temporary table?
maybe below can help you anyway
CREATE TABLE #temp(
Query type)
DECLARE #i INT
SET #i = 1
WHILE #i >= 10
BEGIN
INSERT INTO #temp
SELECT
Query
FROM QueryBuilderQueries
WHERE Query.value('(/Query/QueryGroup/QueryRule/Value)[#i]', 'varchar(max)') LIKE 'UserToFind'
AND Query.value('(/Query/QueryGroup/QueryRule/Attribute)[#i]', 'varchar(max)') IN ('FirstName', 'LastName')
#i = #i + 1
END
SELECT
*
FROM #temp
It's a pity that the SQL Server (I'm using 2008) does not support some XQuery functions related to string such as fn:matches, ... If it supported such functions, we could query right inside XQuery expression to determine if there is any. However we still have another approach. That is by turning all the possible values into the corresponding SQL row to use the WHERE and LIKE features of SQL for searching/filtering. After some experiementing with the nodes() method (used on an XML data), I think it's the best choice to go:
select *
from QueryBuilderQueries
where exists( select *
from Query.nodes('//QueryRule') as v(x)
where LOWER(v.x.value('(Attribute)[1]','varchar(max)'))
in ('firstname','lastname')
and v.x.value('(Value)[1]','varchar(max)') like 'UserToFind')

SQL Server "FOR XML" output from queries joining two tables

I'm new to the "FOR XML" feature in SQL Server. I am using SQL Server 2012.
I have two tables, Word and Word_Expansion.
Sample data:
table [Word]:
WordOID Word
------- ----
1 PIPE
2 WIRE
table [Word_Expansion]:
WEOID fk_WordOID Word_Expansion
----- ---------- --------------
1 2 COAX
2 2 SPEAKER CABLE
3 1 CONDUIT
Now, I would like to produce XML something like:
<expansion>
<sub>WIRE</sub>
<sub>SPEAKER CABLE</sub>
</expansion>
<expansion>
<sub>PIPE</sub>
<sub>CONDUIT</sub>
</expansion>
I have come close with various efforts at crafting XML FOR statements, but I just can't seem to grasp what it is that I need to do to get these two tables mashed into the right XML output. I'll be digging further into XML FOR syntax, but if you have a moment and know this well...
Does anyone have any pointers as to what I should try?
This should do the trick for you:
SQL:
SELECT Word Sub,
(
SELECT Word_Expansion AS Sub
FROM Word_Expansion WE
WHERE WE.fk_WordOID = W.WordOID
FOR XML PATH(''), type
)
FROM Word W
FOR XML PATH ('Expansion')
XML Output:
<Expansion>
<Sub>Pipe</Sub>
<Sub>CONDUIT</Sub>
</Expansion>
<Expansion>
<Sub>Wire</Sub>
<Sub>COAX</Sub>
<Sub>SPEAKER CABLE</Sub>
</Expansion>
Although i'm not sure why you want Word.Word to be classified as "Sub"?
Shouldn't this instead be the parent of Word_Expansion (which should be sub?)
EDIT: I found this link quite useful when looking into FOR XML and nested queries Nested FOR XML
Here is mine... I upvoted the first post because his was fastest, but it does it a little different so I figured it couldn't hurt to add mine...
With groupedWords
As
(
Select WordOID,
Word
From Word
Union
Select fk_WordOID, Word_Expansion
From Word_Expansion
)
Select (Select s.word As sub
From groupedWords s
Where s.WordOID = n.WordOID
For Xml Path(''), Type)
From groupedWords n
Group By n.WordOID
For Xml Path('expansion')

SQL Server 2005 FOR XML Clause

We are having an issue where we are running the exact same query on two different servers, running the exact same service pack and update - 9.0.4211 - but receiving two differently formatted XML resultsets. Does anyone have any idea why/how this is happening?
Is there a setting/schema involved somehow in the way SQL Server generates the resulting XML format? I understand that we can transform the xml with the PATH option but at this point all of the client code is written to use the format from one of the result sets and using the path options still does not get us what the AUTO option does for the correct format.
Query -
SELECT distinct
operation.operationid,
#zoneId as ZoneID,
member.name, IsNull(member.firstname, '') as firstname, IsNull(member.lastname, '') as lastname, IsNull(member.email, '') as email, IsNull(member.memberid, '') as memberid, IsNull(member.type, '') as type, IsNull(member.AppMemberID, '') as AppMemberID
FROM IQSECURE_TaskOperations operation
join IQSECURE_RoleTasks r on operation.taskid = r.taskid
join IQOBASE_Rosters roster on r.roleid = roster.roleid
left outer join IQObase_Members member on roster.rosterid = member.Rosterid
WHERE operation.operationid = #operationid AND roster.zoneid = #zoneId and member.memberid is not null
union
SELECT distinct
operation.operationid,
#zoneID as ZoneID,
member.name, IsNull(member.firstname, '') as firstname, IsNull(member.lastname, '') as lastname, IsNull(member.email, '') as email, IsNull(member.memberid, '') as memberid, IsNull(member.type, '') as type, IsNull(member.AppMemberID, '') as AppMemberID
FROM IQSECURE_TaskOperations operation
join IQSECURE_RoleTasks r on operation.taskid = r.taskid
join IQOBASE_Rosters roster on r.roleid = roster.roleid
left outer join IQOBASE_Members_Exploded member on roster.rosterid = member.Rosterid
WHERE operation.operationid = #operationid AND roster.zoneid = #zoneid and member.memberid is not null
ORDER BY IsNull(member.type, ''), IsNull(member.lastname, ''), IsNull(member.firstname, ''), member.name
FOR XML AUTO, XMLDATA
Returned xml can be provided if need be.
Thanks in advance for any help provided.
Jon
You can check if there are any differences on the database:
SELECT *
FROM sys.configurations
ORDER BY name ;
And I would also check the client you are using. If you are using SQL Management Studio there is a menu option Tools / Options. This has setting that might affect what you are seeing.
This problem was a two part problem. The two databases were not exactly the same, one had SQL 2000 compatibility mode the other SQL 2005. The one with SQL 2000 was generating the correct XML format. So, one fix was to make the other SQL 2000 compatible. The other solution was to rewrite the select without the UNION. For some reason the UNION caused the incorrect XML format.