Returning the results of a select statement that uses a FOR XML PATH('') to condense to one row in a Stored Procedure - sql

I need to pull several values out of some XML that I have and return it as one string from a stored procedure. I have created the select statement that will pull all of the rows into one.
This is the code that I currently have.
CREATE FUNCTION openrpt.getSearchTermNames (#searchID NVARCHAR(MAX))
RETURNS VARCHAR(MAX) AS
BEGIN
DECLARE #xmlData XML
DECLARE #Names XML
SET #xmlData =
(
SELECT QueryXML
FROM ConflictsSearchTerms
WHERE ConflictsSearchTerms.[ID] = #searchID);
WITH xmlnamespaces ( default 'http://schemas.datacontract.org/2004/07/IntApp.Wilco.Model.Conflicts.Searches', 'http://schemas.microsoft.com/2003/10/Serialization/Arrays' AS d2p1, 'http://www.w3.org/2001/XMLSchema-instance' AS i )
RETURN
(
SELECT '; ' + temp.value('.', 'NVARCHAR(MAX)')
FROM #xmlData.nodes('/ConflictsSearchTermQuery/TermItems/d2p1:string') AS XMLDATA(temp)
UNION
SELECT '; ' + temp.value('d2p1:Value[1]', 'NVARCHAR(MAX)') AS [Test]
FROM #xmlData.nodes('/ConflictsSearchTermQuery/CorporateTreeCompaniesById/d2p1:KeyValueOfstringstring') AS XMLDATA(temp) FOR XML PATH('')
)
The select statemt will correctly return a list of the items from those two fields in the XML seperated by semi-colons but I am getting a syntax error at the return . I also get an error that says
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.

Try this:
CREATE FUNCTION openrpt.getSearchTermNames
(
#searchID NVARCHAR(MAX)
)
RETURNS NVARCHAR(MAX)
AS
BEGIN
DECLARE #xmlData XML
DECLARE #Names XML
DECLARE #x XML
SET #xmlData = ( SELECT QueryXML
FROM ConflictsSearchTerms
WHERE ConflictsSearchTerms.[ID] = #searchID
);
WITH XMLNAMESPACES ( DEFAULT 'http://schemas.datacontract.org/2004/07/IntApp.Wilco.Model.Conflicts.Searches', 'http://schemas.microsoft.com/2003/10/Serialization/Arrays' AS d2p1, 'http://www.w3.org/2001/XMLSchema-instance' AS i )
SELECT #x =
( SELECT * FROM (
SELECT '; ' + temp.value('.', 'NVARCHAR(MAX)') AS [Test]
FROM #xmlData.nodes('/ConflictsSearchTermQuery/TermItems/d2p1:string') AS XMLDATA(temp)
UNION
SELECT '; ' + temp.value('d2p1:Value[1]', 'NVARCHAR(MAX)')
FROM #xmlData.nodes('/ConflictsSearchTermQuery/CorporateTreeCompaniesById/d2p1:KeyValueOfstringstring') AS XMLDATA(temp))t
FOR XML PATH('')
)
RETURN CAST(#x AS NVARCHAR(MAX))
END

Related

How to create temp table with dynamic SQL query result

I have this stored procedure:
Declare #MarketID AS NVARCHAR(MAX) = '1.136529848';
Declare #UserID AS NVARCHAR(MAX) = '6a309d84-d1c6-434d-b9df-4f96a74da912';
DECLARE #colsSelect AS NVARCHAR(MAX);
DECLARE #colsTemp AS NVARCHAR(MAX);
DECLARE #query AS NVARCHAR(MAX);
SELECT
#colsSelect = STUFF((SELECT distinct ',' +
'''''' + ' as ' + QUOTENAME(name)
FROM RunnersInfoes AS t
WHERE marketID = #MarketID
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') , 1, 1, '');
PRINT #colsSelect
SET #query= ';WITH cte AS
(
SELECT
id, ParentId, 0 AS Level, Share, AccountTypeName, FirstName
FROM
dbo.View_UserProfile
WHERE
View_UserProfile.id = ' + '''' + #UserID + '''' +'
UNION ALL
SELECT
t.id, t.ParentId, Level + 1 AS Level, t.Share, t.AccountTypeName, t.FirstName
FROM
View_UserProfile t
INNER JOIN
cte ON t.ParentId = cte.id
)
SELECT
ID, AccountTypeName AS Type, FirstName AS Name, ' + #colsSelect + '
FROM cte AS t'
EXECUTE (#query)
and it's generating this result:
I want to create temp table or variable type table for following result , remember the column of this result are dynamically rendered. Sometimes result returns more columns and sometimes with less but first 3 columns remain the same for every result. So kindly help for creating dynamic table inside the stored procedure.
You can do:
SELECT ID
, AccountTypeName AS Type
, FirstName AS Name
, ' + #colsSelect + '
INTO ##TEMPTABLE
FROM cte AS t
Since you execute this dynamically, you cannot use #TEMPTABLE because a local temp table will only exist in the scope of the query that defines it. Using ## creates a global temp table which will be accessible outside the scope of the dynamic query.
Please use the SELECT - INTO clause for your use case as given below
SELECT * INTO #temptable FROM cte
To create a temp table that is filled by a dynamic query, use global temp tables like this example.
For the select ... into ... statement to work, you need to make sure every column from the select has a name.
declare #query varchar(1000) = 'select 1 as ID, ''test'' as Column_1 into ##mytable'
exec (#Query)
select * from ##mytable
drop table ##mytable
Do not forget to drop the temp table when your done.

Retrieving the only value from XML string

Here is a my XML string of datatype nvarchar(MAX):
declare #string Nvarchar(MAX)
set #string='<ROOT><Data C="1" /><Data C="2" /><Data C="3" /></ROOT>'
Expected result:
#c='1,2,3'
i want to check that the value of "C" is exists in table or not
You can use the following code to get the values in tabular format:
declare #string Nvarchar(MAX)
set #string='<ROOT><Data C="1" /><Data C="2" /><Data C="3" /></ROOT>'
DECLARE #StringXML XML = CAST(#string as XML);
SELECT T.c.value('(./#C)[1]', 'INT')
FROM #StringXML.nodes('ROOT/Data') T(c);
Then, you can apply the EXIST clause.
SELECT STUFF
(
(
SELECT ',' + T.c.value('(./#C)[1]', 'VARCHAR(12)')
FROM #StringXML.nodes('ROOT/Data') T(c)
FOR XML PATH(''), TYPE
).value('.', 'VARCHAR(MAX)')
,1
,1
,''
);

Pivot TSQL table with dynamic columns

I am passing up JSON as a parameter to a SQL stored proc. I use a function that takes a JSON dictionary and creates a table with key value pairs (two columns) that I then use with a COALESCE to create dynamic sql for an INSERT statement. This works fine for a single dictionary, but I need to also be able to send up JSON string that contains an array of dictionaries. Right now, my parse function gives me this table variable:
What I need is a table variable like this:
I can get the column names from the first table with this:
SELECT DISTINCT element name from #JSONTable
I should mention that these elementname's can and will change. I will not know the number of distinct elementname values.
UPDATE - Using Umair's answer, I am getting close:
DECLARE #JSONString AS VARCHAR(MAX)
SET #JSONString = '[{"ravid":3,"ravversion":2,"taskid":3},{"ravid":4,"ravversion":7,"taskid":99}]'
IF OBJECT_ID('tempdb..#JSONTable') IS NOT NULL
DROP TABLE #JSONTable
CREATE TABLE #JSONTable
(
elementname VARCHAR(500) ,
elementvalue VARCHAR(500)
)
INSERT INTO #JSONTable
( elementname ,
elementvalue
)
SELECT NAME ,
StringValue
FROM dbo.parseJSON(#JSONString)
WHERE LEN(StringValue) > 0 AND NAME IS NOT NULL
--declare a csv variable with all the distinct elements
DECLARE #csv NVARCHAR(max) = STUFF(
(
SELECT ',' + elementname
FROM (
SELECT DISTINCT elementname
FROM #JSONTable
) AS e
FOR XML PATH(''), TYPE
).value('.', 'nvarchar(max)'),
1,
1,
''
);
DECLARE #sql NVARCHAR(MAX) = '
SELECT *
FROM (
SELECT *, Row = ROW_NUMBER() OVER (PARTITION BY elementname ORDER BY elementname)
FROM #JSONTable
) AS t
PIVOT (
MAX(elementvalue)
FOR elementname IN (' + #csv + ')
) AS p
'
EXEC sp_executesql #sql
But the dictionary values don't correspond to the key. Here is the results of Umair's current answer:
How about
--declare a csv variable with all the distinct elements
DECLARE #csv NVARCHAR(max) = STUFF(
(
SELECT ',' + elementname
FROM (
SELECT DISTINCT elementname
FROM #JSONTable
) AS e
FOR XML PATH(''), TYPE
).value('.', 'nvarchar(max)'),
1,
1,
''
);
DECLARE #sql NVARCHAR(MAX) = '
SELECT *
FROM (
SELECT *, Row = ROW_NUMBER() OVER (PARTITION BY elementname ORDER BY elementvalue)
FROM #JSONTable
) AS t
PIVOT (
MAX(elementvalue)
FOR elementname IN (' + #csv + ')
) AS p
'
EXEC sp_executesql #sql
i.e dynamic pivoting :)
Edit:
Since you do not want to aggregate by anything in the pivot, I added a row number function to assign each distinct elementname a sequentially increasing id (based on element value). This will essentially group the pivot by this row column, producing all the required rows.

how to split and concatenate in sql server?

I am passing in a string into a stored procedure to be used in a select statement using dynamic sql:
#groups as nvarchar(1000) = 'group1,group10,group8'
I might just pass in string of numbers, eg, '1,2,3,4'
I want to split these values and then concatenate them so that they end up in the following manner :
'rmc.group1,rmc.group10,rmc.group8'
declare #groups nvarchar(1000) ='group1,group10,group8'
set #groups = 'rmc.' + replace(#groups, ',', ',rmc.')
select #groups
Result:
rmc.group1,rmc.group10,rmc.group8
Sql Fiddle Demo
Select Replace('group1,group10,group8','group','rmc.group')
Try this one -
DECLARE #groups nvarchar(1000) = 'group1,group10,group8'
SELECT STUFF((
SELECT ',rmc.' + t
FROM (
SELECT t = t.c.value('.', 'VARCHAR(50)')
FROM (
SELECT ID = CAST ('<t>' + REPLACE(#groups, ',', '</t><t>') + '</t>' AS XML)
) r
CROSS APPLY ID.nodes ('/t') t(c)
) t
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1,1, '')
Output -
------------------------------------
rmc.group1,rmc.group10,rmc.group8

SQL- fetch value from XML parent node (separately)

In my below Query it's return all the recode set as a XML into a single variable.But i need all the parent node values into separate while loop.Just run the below query:
---------Just Declare the temp Table -------------------------------------------------
IF OBJECT_ID('tempdb.dbo.##TestTable','U')IS NOT NULL DROP TABLE ##TestTable
CREATE TABLE ##TestTable(id int,Uname nvarchar(max),Uaddress nvarchar(max))
INSERT INTO ##TestTable values (1,'abc','NY')
INSERT INTO ##TestTable values (2,'def','WD')
INSERT INTO ##TestTable values (3,'','KL')
DECLARE #XML XML
DECLARE #WhereClause nvarchar(max)
DECLARE #CountVal int
SELECT #CountVal=count(*) from ##TestTable
SET #XML= (SELECT * FROM ##TestTable FOR XML PATH('ParentNode'), ELEMENTS XSINIL)
SELECT #XML
;with cte as
( select xr.value('fn:local-name(.)','nvarchar(max)') name, xr.value('.','nvarchar(max)') val from #xml.nodes('//.') xq(xr)
where xr.value('fn:local-name(.)','nvarchar(max)')<>''
)
SELECT #WhereClause= STUFF((select ' and ' + name + '='''+val+'''' from cte for xml path('')),1,4,'')
SELECT #WhereClause
WHILE (#CountVal>0)
BEGIN
SELECT #WhereClause
SET #CountVal=#CountVal-1
END
IF OBJECT_ID('tempdb.dbo.##TestTable','U')IS NOT NULL DROP TABLE ##TestTable
Current sample XML(in #XML):
<ParentNode xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><id>1</id><Uname>abc</Uname><Uaddress>NY</Uaddress></ParentNode><ParentNode xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><id>2</id><Uname>def</Uname><Uaddress>WD</Uaddress></ParentNode><ParentNode xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><id>3</id><Uname /><Uaddress>KL</Uaddress></ParentNode>
Current the output of #WhereClause is (all into in a single #WhereClause variable):
ParentNode='1abcNY' and id='1' and Uname='abc' and Uaddress='NY' and ParentNode='2defWD' and id='2' and Uname='def' and Uaddress='WD' and ParentNode='3KL' and id='3' and Uname='' and Uaddress='KL'
But my Expected output is:
Firstly(in #WhereClause): id='1' and Uname='abc' and Uaddress='NY'
Secondly(in #WhereClause):id='2' and Uname='def' and Uaddress='WD'
Thirdly(in #WhereClause):id='3' and Uname='' and Uaddress='KL'
.
.
How i get it. Thanks in advance.
Try this:
declare #WhereClause nvarchar(max)
declare #CountVal int
select #CountVal=count(*)
from ##TestTable
while #CountVal>0
begin
select #WhereClause =
(
select ' and '+T.N.value('local-name(.)', 'nvarchar(max)')+'='+T.N.value('.', 'nvarchar(max)')
from (
select *
from ##TestTable
where id = #CountVal
for xml path(''), type
) as C(X)
cross apply C.X.nodes('/*') as T(N)
for xml path(''), type
).value('substring((./text())[1], 6)', 'nvarchar(max)')
select #WhereClause
set #CountVal=#CountVal-1
end
seem to be late and having missunderstood, that woul habe been my approach
DECLARE #XML XML
DECLARE #WhereClause nvarchar(max)
DECLARE #CountVal int
SELECT #CountVal=count(*) from ##TestTable
SET #XML= (SELECT * FROM ##TestTable FOR XML PATH('ParentNode'), ELEMENTS XSINIL)
SELECT #XML
;with cte as
( select xr.value('fn:local-name(.)','nvarchar(max)') name, xr.value('.','nvarchar(max)') val from #xml.nodes('//.') xq(xr)
where xr.value('fn:local-name(.)','nvarchar(max)')<>'' and xr.value('fn:local-name(.)','nvarchar(max)')<>'ParentNode'
)
SELECT #WhereClause= SubString((select Case when Name ='id' then CHAR(10) +''+ name + '='''+val+'''' else ' and ' + name + '='''+val+'''' end from cte for xml path('')),2,100000000)
Print #WhereClause