Using "for xml" to format SQL results that include results that are NULL? - sql

I have an SQL query basically as follows:
DECLARE #BODY1 NVARCHAR(MAX)
SET #BODY1 = CAST((SELECT td = Name + '</td><td>' + Number + '</td><td>' + Address + '</td>'
FROM
(
SELECT
Name, Number, Address
FROM
Table1
) as Sub
FOR XML PATH('tr'), type) AS VARCHAR(MAX))
SET #BODY1 = '<TABLE CELLPADDING="3" CELLSPACING="3" BORDER="1">'+
'<TR><TH>Name</TH><TH>Number</TH><TH>Address</TH></TR> +
+ REPLACE(REPLACE(#Body1, '<','<'), '>','>') + '</TABLE>'
EXEC MSDB.DBO.SP_SEND_DBMAIL
#PROFILE_NAME = 'NAME',
#RECEPIENTS = 'NAME#DOMAIN.COM',
#BODY = #Body1,
#SUBJECT = 'Details',
#BODY_FORMAT = 'HTML',
#EXECUTE_QUERY_DATABASE = 'NAME';
The data I have can be summarised as follows:
NAME NUMBER ADDRESS
Bob 12345 1 Street, Town
John 23456
Scott 34567 3 Avenue, City
When I run this code which sends me an email containing the results of the query, I only get Bob and Scott's record. This example is simplified, but if there are any rows that do not have data in each field then they do not show in the email.
I've read somewhere that perhaps this is due to needing another variable as part of the XML code, but I can't quite put my finger on what it is. Please can someone assist me?
Thanks in advance.

Your primary issue is that + will return null if any of the values are null. So you could use either ISNULL or CONCAT
But this is in any case not the correct way to create XML. You should just unpivot the values and use FOR XML properly.
DECLARE #BODY1 NVARCHAR(MAX) =
(
SELECT
ISNULL(v.td, '') AS td
FROM
Table1
CROSS APPLY (VALUES
(Name),
(Number),
(Address)
) v(td)
FOR XML PATH('tr')
);

You need to be able to prepare for the entire output of this expression to be NULL:
SET #BODY1 = CAST((SELECT td = Name + '</td><td>'
+ Number + '</td><td>'
+ Address + '</td>' ...
A couple of ways to handle that. You can use COALESCE to convert NULL to empty string:
SET #BODY1 = CAST((SELECT td = COALESCE(Name, '') + '</td><td>'
+ COALESCE(Number, '') + '</td><td>'
+ COALESCE(Address, '') + '</td>' ...
Or CONCAT(), which does that for you:
SET #BODY1 = CAST((SELECT td = CONCAT
(Name, '</td><td>', Number, '</td><td>', Address, '</td>') ...
There are also certainly other approaches to your entire problem space that are a lot less messy, but this is at least a start to get your missing row back.
For example, on SQL Server 2017, you can use STRING_AGG() and CONCAT_WS():
SELECT #BODY1 = '<table ...>
<TR><TH>Name</TH><TH>Number</TH><TH>Address</TH></TR><tr>'
+ STRING_AGG('<td>'+CONCAT_WS('</td><td>',Name,Number,Address)
+'</td>','</tr><tr>') + '</tr></table>'
FROM dbo.Table1;
This is also, admittedly, ugly. Another way:
SELECT #BODY1 = '<table ...>
<TR><TH>Name</TH><TH>Number</TH><TH>Address</TH></TR>
<tr>' + td + '</table>'
FROM
(
SELECT td FROM
(
SELECT Name = COALESCE(Name, ''),
Number = COALESCE(Number,''),
Address = COALESCE(Address,'')
FROM dbo.Table1
) AS cp UNPIVOT(td FOR cols IN (Name, Number, Address)) AS up
FOR XML PATH('tr')
) AS x(td);

Please try the following XQuery based approach that gererates XHTML for the email.
Notable points:
No strings concatenation.
No worries for NULL values.
Very easy to create, very easy to maintain.
UI styling is controlled via CSS.
SQL
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, [Name] VARCHAR(20), Number CHAR(5), [Address] VARCHAR(100));
INSERT INTO #tbl (Name, Number, Address) VALUES
('Bob ', '12345' ,'1 Street, Town'),
('John ', '23456' , NULL),
('Scott', '34567' ,'3 Avenue, City');
DECLARE #xhtmlBody XML
, #body NVARCHAR(MAX)
, #tableCaption VARCHAR(30) = 'Customers list';
SET #xhtmlBody = (SELECT (
SELECT * FROM #tbl FOR XML PATH('row'), TYPE, ROOT('root'))
.query('<html><head>
<meta charset="utf-8"/>
(: including embedded CSS styling :)
<style>
table <![CDATA[ {border-collapse: collapse; width: 300px;} ]]>
th <![CDATA[ {background-color: #4CAF50; color: white;} ]]>
th, td <![CDATA[ { text-align: left; padding: 8px;} ]]>
tr:nth-child(even) <![CDATA[ {background-color: #f2f2f2;} ]]>
#green <![CDATA[ {background-color: lightgreen;} ]]>
</style>
</head>
<body>
<table border="1">
<caption><h2>{sql:variable("#tableCaption")}</h2></caption>
<thead>
<tr>
<th>No.</th>
<th>Name</th>
<th>Number</th>
<th>Address</th>
</tr>
</thead>
<tbody>
{
for $row in /root/row
return <tr>
<td>{data($row/ID)}</td>
<td>{data($row/Name)}</td>
<td>{data($row/Number)}</td>
<td>{data($row/Address)}</td>
</tr>
}
</tbody></table></body></html>'));
SELECT #xhtmlBody;
SET #body = CAST(#xhtmlBody AS NVARCHAR(MAX));
Output

Related

SQL Cursor Problem CODE 16915 Cursor name already exists

I have a problem with a cursor inside SQL Server stored procedure.
Here is the code:
if (#pEvento = 84)
begin
set #pAsun_mail = #pAsun_mail + ' FUP ' + CONVERT(varchar(10), #pFupID) + ' ' + #pVersion;
DECLARE #ConsecutivoTemp int, #FechaTemp date, #ValorTemp money, #CondicionTemp varchar(50), #GeneraBoletoTemp bit;
DECLARE CondicionPago_Cursor CURSOR FOR
SELECT fccp_Consecutivo, Fecha, Valor, Condicion, fccp_BoletosBancarios FROM [dbo].[fup_CuotasCondicionesPago]
WHERE fccp_entrada_cot_id = (SELECT [eect_id]
FROM fup_enc_entrada_cotizacion
WHERE [eect_fup_id] = #pFupID
AND [eect_vercot_id] = #pVersion) AND fccp_TipoPago_id = 3;
OPEN CondicionPago_Cursor;
FETCH NEXT FROM CondicionPago_Cursor INTO
#ConsecutivoTemp, #FechaTemp, #ValorTemp, #CondicionTemp, #GeneraBoletoTemp;
DECLARE #HTMLTableLeasing varchar(max);
WHILE ##FETCH_STATUS = 0
BEGIN
SET #HTMLTableLeasing = #HTMLTableLeasing + '<tr>';
SET #HTMLTableLeasing = #HTMLTableLeasing + '<td>'+ CONVERT(varchar(3), #ConsecutivoTemp) +'</td>';
SET #HTMLTableLeasing = #HTMLTableLeasing + '<td>'+ CONVERT(varchar(20), #FechaTemp) +'</td>';
SET #HTMLTableLeasing = #HTMLTableLeasing + '<td>'+ CONVERT(varchar(15), #ValorTemp) +'</td>';
SET #HTMLTableLeasing = #HTMLTableLeasing + '<td>'+ #CondicionTemp +'</td>';
IF #GeneraBoletoTemp = 1
BEGIN
SET #HTMLTableLeasing = #HTMLTableLeasing + '<td><input type="checkbox" disabled checked /></td>';
END
ELSE
BEGIN
SET #HTMLTableLeasing = #HTMLTableLeasing + '<td><input type="checkbox" disabled/></td>';
END
SET #HTMLTableLeasing = #HTMLTableLeasing + '</tr>';
FETCH NEXT FROM CondicionPago_Cursor INTO
#ConsecutivoTemp, #FechaTemp, #ValorTemp, #CondicionTemp, #GeneraBoletoTemp;
END
CLOSE CondicionPago_Cursor
DEALLOCATE CondicionPago_Cursor
set #pMsg = #pMsg + #HTMLTableLeasing
end
And the error says:
Already exists a cursor with name 'CondicionPago_Cursor'
I tried checking again the order or STATEMENTS OPEN, FETCH, CLOSE, DEALLOCATE but I think they have a correct order.
I'm tryin to iterate over a set or records to create dynamically a body of a table, you can see the tags <th> and <td>.
As #Lamu already mentioned, there are better ways to compose (X)HTML.
Also, there is no need to concatenate strings like in the #JohnInk answer.
Here is a conceptual example for you, including CSS for styling.
It will work starting from SQL Server 2005 onwards.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (
ID INT IDENTITY PRIMARY KEY
, state CHAR(2)
, city VARCHAR(30)
);
INSERT INTO #tbl (state, city)
VALUES
('FL', 'Miami')
, ('CA', 'Los Angeles')
, ('TX', 'Austin');
-- DDL and sample data population, end
DECLARE #xhtmlBody XML
, #body NVARCHAR(MAX)
, #tableCaption VARCHAR(30) = 'US states and cities';
SET #xhtmlBody = (SELECT (
SELECT * FROM #tbl FOR XML PATH('row'), TYPE, ROOT('root'))
.query('<html><head>
<meta charset="utf-8"/>
(: including embedded CSS styling :)
<style>
table <![CDATA[ {border-collapse: collapse; width: 300px;} ]]>
th <![CDATA[ {background-color: #4CAF50; color: white;} ]]>
th, td <![CDATA[ { text-align: left; padding: 8px;} ]]>
tr:nth-child(even) <![CDATA[ {background-color: #f2f2f2;} ]]>
td:nth-child(3) <![CDATA[ {background-color: red;} ]]>
#green <![CDATA[ {background-color: lightgreen;} ]]>
</style>
</head>
<body>
<table border="1">
<caption><h2>{sql:variable("#tableCaption")}</h2></caption>
<thead>
<tr>
<th>No.</th>
<th>State</th>
<th>City</th>
</tr>
</thead>
<tbody>
{
for $row in /root/row
return <tr>
<td>{data($row/ID)}</td>
<td>{data($row/state)}</td>
<td>
{if ($row/city/text()="Los Angeles") then attribute id {"green"} else ()}
{data($row/city)}
</td>
</tr>
}
</tbody></table></body></html>'));
SELECT #xhtmlBody;
Output
Saved as a file, and tested in any Internet browser
First: the error comes from using the global cursor. So, every time you run this it will run into itself. Add a LOCAL keyword.
DECLARE CondicionPago_Cursor CURSOR LOCAL FOR
But, you want to avoid cursor loops whenever possible. They are much less efficient. You might do something like instead.
SELECT #HTMLTableLeasing = #HTMLTableLeasing + '<tr><td>' + CAST(fccp_Consecutivo
AS varchar(3)) + '</td><td>' +
CAST(Fecha AS varchar(20)) + '</td><td>' +
CAST(Valor AS varchar(15)) + '</td><td>' +
Condicion + '</td><td>' +
CASE WHEN GeneraBoleto = 1
THEN '<input type="checkbox" disabled checked />'
ELSE '<input type="checkbox" disabled/>' END +
'</td></tr>'
FROM [dbo].[fup_CuotasCondicionesPago]
WHERE fccp_entrada_cot_id = (SELECT [eect_id]
FROM fup_enc_entrada_cotizacion
WHERE [eect_fup_id] = #pFupID
AND [eect_vercot_id] = #pVersion) AND fccp_TipoPago_id = 3

How to convert string which is output of select .....from for JSON AUTO to JSON Formatted file which is readable without using third party tool SSIS

HI I am writing SSIS package to get the output from
Select a,b,c from CUST FOR JSON AUTO
However I am getting output in a single row like
{"a":"Rock" ,"b":"paper" ,"c":"scissors"}, {"a":"Rock" ,"b":"paper" ,"c":"scissors"}, {"a":"Rock" ,"b":"paper" ,"c":"scissors"}....
However I want output as
{
"a":"Rock",
"b":"paper",
"c":"scissors"
},
{
"a":"Rock",
"b":"paper",
"c":"scissors"
},
{
"a":"Rock",
"b":"paper",
"c":"scissors"
},
My client argument is the Json file will be big file and he don't want to do extra formatting and should be readable
If you can add a javascript component to SSIS, it can be done.
(I'm not sure on how to do that in SSIS). But here is how you do it in javascript
I have a way to get this done rather messy way, but you can see whether that serves you the purpose
DECLARE #nl varchar(2) = char(13), #Json nvarchar(MAX) = (Select a,b,c from #CUST FOR JSON AUTO)
Select #Json = Replace(#Json, '[{','[' + #nl + '{' + #nl)
Select #Json = Replace(#Json, '{','{' + #nl)
Select #Json = Replace(#Json, '","','",' + #nl + '"' )
Select #Json = Replace(#Json, '"},{','"' + #nl + '},' + #nl + #nl + '{' )
Select #Json = Replace(#Json, '"}]','"' + #nl + '}' + #nl + ']' + #nl + #nl)
Select #Json as FormattedJSON
And here is the fiddle with more improvements

How to correct the scalar variable declaration error in my SQL job?

I am using SQL Server 2012 and I have the following stored procedure which is returning the required output in the form of a HTML table:
CREATE PROCEDURE dbo.ITB_SendEmail
AS
BEGIN
DECLARE #Body NVARCHAR(MAX),
#Body2 NVARCHAR(MAX),
#TableHead VARCHAR(1000),
#TableTail VARCHAR(1000)
SET #TableTail = '</table></body></html>' ;
SET #TableHead = '<html><head>' + '<style>'
+ 'td {border: solid black;border-width: 1px;padding-left:5px;padding-right:5px;padding-top:1px;padding-bottom:1px;font: 11px arial} '
+ '</style>' + '</head>' + '<body>' + 'Report generated on : '
+ CONVERT(VARCHAR(50), GETDATE(), 106)
+ ' <br> <table cellpadding=0 cellspacing=0 border=0>'
+ '<tr> <td bgcolor=#E6E6FA><b>StayYear</b></td>'
+ '<td bgcolor=#E6E6FA><b>Market</b></td>'
+ '<td bgcolor=#E6E6FA><b>Jan</b></td>'
+ '<td bgcolor=#E6E6FA><b>Feb</b></td>'
+ '<td bgcolor=#E6E6FA><b>Mar</b></td>'
+ '<td bgcolor=#E6E6FA><b>Apr</b></td>'
+ '<td bgcolor=#E6E6FA><b>May</b></td>'
+ '<td bgcolor=#E6E6FA><b>Jun</b></td>'
+ '<td bgcolor=#E6E6FA><b>Jul</b></td>'
+ '<td bgcolor=#E6E6FA><b>Aug</b></td>'
+ '<td bgcolor=#E6E6FA><b>Sep</b></td>'
+ '<td bgcolor=#E6E6FA><b>Oct</b></td>'
+ '<td bgcolor=#E6E6FA><b>Nov</b></td>'
+ '<td bgcolor=#E6E6FA><b>Dec</b></td>';
SET #Body = ( SELECT td = StayYear, '',
td = Market, '',
td = Jan, '',
td = Feb, '',
td = Mar, '',
td = Apr, '',
td = May, '',
td = Jun, '',
td = Jul, '',
td = Aug, '',
td = Sep, '',
td = Oct, '',
td = Nov, '',
td = Dec, ''
FROM View1
FOR XML RAW('tr'),
ELEMENTS
)
SET #Body2 = #TableHead + ISNULL(#Body, '') + #TableTail
SELECT #Body2
END
I have now set up a SQL job which is supposed to execute this stored procedure and emails the output to a recipient. My SQL Server job runs a T-SQL query (see below):
DECLARE #GeneratedHTML NVARCHAR(MAX);
EXEC ITB_SendEmail #GeneratedHTML = #Body2 OUTPUT
EXEC sp_send_dbmail
#profile_name='BI',
#copy_recipients ='',
#recipients='xxx#yyyy.com',
#subject='ITB',
#body= #GeneratedHTML ,
#body_format = 'HTML' ;
However, the SQL Server job is failing with the following an error message:
Must declare the scalar variable #Body2. [SQLSTATE 42000] (Error 137). The step failed
I cannot figure out the scalar variable declaration issue. What am I doing wrong?
The error is not referring to the variable in your Stored Procedure code if that's what you're thinking.
It's saying you need to DECLARE #Body2 in your Execution Batch. However you have more problems than that. You are trying to access an output parameter of your stored procedure, but in your stored procedure you haven't got an output parameter.
Reading the documentation on Output parameters would be a good start.
Assuming you correctly set #Body2 as an output parameter in your stored procedure, then you simply need to reverse their order in the execution statement:
DECLARE #GeneratedHTML NVARCHAR(MAX);
EXEC ITB_SendEmail #Body2 = #GeneratedHTML OUTPUT
EXEC sp_send_dbmail
#profile_name='BI',
#copy_recipients ='',
#recipients='xxx#yyyy.com',
#subject='ITB',
#body= #GeneratedHTML ,
#body_format = 'HTML' ;

how to bypass the 65535 character limit in a select statement using "FOR XML"

I am aware of the 65535 truncation for text datatypes (and Varchar(MAX) as well). I am also aware of XML outputs that can be set to unlimited. I have a table that stores XML strings in a varchar(MAX) column called GEOM.
My problem is that the xml snippet held in the geom column can exceed 65535 characters. I figure since it's XML, and I'm creating an XML output in my code anyways, why not just build the xml and send that out as such, since I can set XML output to "Unlimited".
USE [buyerhero]
GO
/****** Object: StoredProcedure [dbo].[GEOIDKMLCOUNTY] Script Date: 9/17/2015 11:18:55 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[GEOIDKMLCOUNTY] #CountyID nvarchar(30)
AS
DECLARE #kml XML
DECLARE #kmlout NVARCHAR(MAX)
SELECT #kml = CAST('<?xml version="1.0" encoding="utf-16" ?>' +
'<kml xmlns="http://www.opengis.net/kml/2.2">' +
'<Document>' +
' <Style id="Licensed">
<LineStyle>
<color>ff000000</color>
<width>2</width>
</LineStyle>
<PolyStyle>
<color>1e1400FF</color>
<fill>1</fill>
<outline>1</outline>
</PolyStyle>
</Style>
<Style id="NotLicensed">
<LineStyle>
<color>ff000000</color>
<width>2</width>
</LineStyle>
<PolyStyle>
<color>1e14F0FF</color>
<fill>1</fill>
<outline>1</outline>
</PolyStyle>
</Style>
<Style id="Other">
<LineStyle>
<color>ff000000</color>
<width>2</width>
</LineStyle>
<PolyStyle>
<color>1e007800</color>
<fill>1</fill>
<outline>1</outline>
</PolyStyle>
</Style>' +
(
select
'<![CDATA[{"County":"' + r.CountyName + ', ' + r.State + '", "GEOID": "'+t.GEOID+'"}]]>' as Name,
case t.IsLicensed
when 2 then '#Licensed'
when 1 then '#NotLicensed'
else '#Other'
end as StyleURL,
cast(replace(geom,'"','') as xml) as Geometry
from Tracts t
join census_county_ref c on t.GEOID = c.GEOID
join FIPSCountyCode r on c.STATEFP = r.StateANSI and c.COUNTYFP = r.CountyANSI
where r.CountyID = #CountyID
FOR XML PATH(''), ELEMENTS) + '</Document></kml>' AS XML)
--
-- Perform replacement of < and > with < and > respectively
--
SET #kmlout = REPLACE(REPLACE(CAST(#kml AS NVARCHAR(MAX)), '<', '<'), '>', '>')
SET #kmlout = REPLACE(#kmlout, 'utf-16', 'utf-8')
--
-- Return kmlout
--
SELECT #kmlout
in spite of the idea the geom columns is xml and I'm using cast(replace(geom,'"','') as xml) which is varchar(max), that field still gets truncated.
How do I "untruncate" the field so I can output the XML?
Thanks.
Use the concat function instead the + operator. the plus operator is limited to 8000 bytes.
SELECT #kml =CAST(concat('your xml', the select,'the other xml')

Sql Server - Is there any way to `Concat` nvarchar column in Select Such as `Agregate functions`

Hi I Have Table that called Tags, in tag table I have 2 columns (QuestionID int ,Tag nvachar(100))
I want to Select Questions with all Tags in one column like the below
QuestionID Tag
---------- ----
1 Math
1 Integral
2 Physics
QuestionID QuestionText
---------- -----------
1 What is 2*2?
2 What is Quantom roles?
QuestionID QuestionText Tags
---------- ----------- -------
1 What is 2*2? Math, Integral
2 What is Quantom roles? Physics
Can any one help me with out using scalar value function
There are two ways to answer this:
can use a query like in other answer, but this is work for one table only.
create clr aggregate function for this like a below code (my code in C#).
this solution work for all tables and simple for use,
only use: select Concat(column) from Table in sql server
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Text;
[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedAggregate(Format.UserDefined, IsInvariantToDuplicates = false, IsInvariantToNulls = true, IsInvariantToOrder = false, IsNullIfEmpty = true, MaxByteSize = -1)]
public struct Concat : IBinarySerialize
{
public void Init()
{
SB = new StringBuilder();
}
public void Accumulate(SqlString Value)
{
if (Value.IsNull)
return;
if (SB.Length > 0)
SB.Append("\n");
SB.Append(Value);
}
public void Merge(Concat Group)
{
if (SB.Length > 0 && Group.SB.Length > 0)
SB.Append("\n");
SB.Append(Group.SB.ToString());
}
public SqlString Terminate()
{
return new SqlString(SB.ToString());
}
// This is a place-holder member field
StringBuilder SB;
public void Read(System.IO.BinaryReader r)
{
SB = new StringBuilder(r.ReadString());
}
public void Write(System.IO.BinaryWriter w)
{
w.Write(SB.ToString());
}
}
CREATE TABLE #temp
(
QuestionID INT,
Tag NVARCHAR(100)
)
INSERT INTO #temp
(QuestionID,Tag)
VALUES (1,N'Math'),
(1,N'Integral'),
(2,N'Physics')
CREATE TABLE #temp1
(
QuestionID INT,
QuestionText NVARCHAR(100)
)
INSERT INTO #temp1
(QuestionID,QuestionText)
VALUES (1,N'What is 2*2?'),
(2,'What is Quantom roles?')
SELECT h.QuestionID,
h.QuestionText,
Stuff((SELECT ', ' + CONVERT(VARCHAR, b.TAG)
FROM #temp b
WHERE b.QuestionID = h.QuestionID
FOR XML PATH('')), 1, 2, '')
FROM #temp t
JOIN #temp1 h
ON t.QuestionID = h.QuestionID
GROUP BY h.QuestionID,
h.QuestionText
SELECT q.QuestionText
,STUFF((
SELECT ', ' + t2.Tag
FROM Tags t2
WHERE t1.QuestionID = t2.QuestionID
ORDER BY t2.Tag
FOR XML PATH('')
,TYPE
).value('.', 'varchar(max)'), 1, 2, '') AS Tag
FROM Questions q
INNER JOIN Tags t1
ON q.QuestionID = t1.QuestionID
GROUP BY q.QuestionText
,t1.QuestionID
Working example : http://sqlfiddle.com/#!3/e8f0f/7
Try this
create function fn_comma (#question_id int)
returns varchar(100)
as
begin
declare #value varchar(100)
set #value=(SELECT top 1 STUFF((SELECT ', ' + CAST(Value AS VARCHAR(10)) [text()]
FROM Tags
WHERE ID = t.ID
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,2,' ') List_Output
FROM Tags
--where id=1
GROUP BY ID)
return #value
end
Try sub query to concat column data in comma separated values like below :
SELECT [QuestionID],
[QuestionText],
STUFF(( SELECT ',' + [Tag]
FROM [dbo].[Tags]
WHERE [QuestionID] = [Question].[QuestionID]
FOR XML PATH ('')), 1, 1, '') AS [Tags]
FROM [dbo].[Question]
SQL Fiddle Demo
Try the below idea. You just need to rewrite it as a function, then it will return all tags for the question id:
declare #function_in_questionid_para as #int
with std as
(select *,ROW_NUMBER() over(partition by QuestionID order by QuestionID,tag) as dd from #temp)
select * #temp3 into from std
declare #counter as int
set #counter = (select count(*) from #temp where QuestionID = #function_in_questionid_para as #int)
declare #c as int = 1
declare #tags as varchar(200) = ''
while (#c <= #counter)
begin
if (#c > 1) set #tags = #tags + ', '
set #tags = #tags + (select tag from #temp3 where QuestionID = #function_in_questionid_para as #int and dd = #c)
set #c = #c + 1
end
print #tags