Issue not getting a result when stuff is used - sql

I am using the stuff function to create an comma separated value
stuff works if I run it alone, but when I use in combination with another column to check against, it is failing.
Is it due to datatype issue?
Here is my code
and cast(verifyemails as varchar(max)) in (select STUFF((SELECT Distinct ',' + '''' + cast(emails as varchar(max)) + '''' from roleslist
left join users on users.fkuserid = roleslist.fkroleuserid
where
and fkUserID = 350
group by emails
FOR XML PATH('')), 1,1,'')
The above does not give the results, even the emails do exists in the table, but the below query is working if I run it alone. Does it have to anything with trim or anything?
select STUFF((SELECT Distinct ',' + '''' + cast(emails as varchar(max)) + '''' from roleslist
left join users on users.fkuserid = roleslist.fkroleuserid
where
and fkUserID = 350
group by emails
FOR XML PATH('')), 1,1,'')

If you're doing an IN you shouldn't bother creating a comma-delimited string. If you use a comma-delimited string you need to use LIKE instead of IN. Should be something like this...
and
(select STUFF((SELECT Distinct ',' + '''' + cast(emails as varchar(max)) + ''''
from roleslist
left join users
on users.fkuserid = roleslist.fkroleuserid
where fkUserID = 350
group by emails
FOR XML PATH('')), 1,1,'') LIKE '%' + cast(verifyemails as varchar(max)) + '%'
Or you could simply remove the comma-delimiting stuff and do this...
and cast(verifyemails as varchar(max)) in
(select cast(emails as varchar(max)) from roleslist
left join users
on users.fkuserid = roleslist.fkroleuserid
where fkUserID = 350
group by emails)

Related

Remove leading comma from FOR XML PATH function

I created a variable that accepts multiple string values using the FOR XML PATH:
set #Control_Number =
(SELECT DISTINCT
SUBSTRING(
(
SELECT ''', '''+ co.control_number AS [text()]
FROM #AGBCaseCompanyMap2 co
WHERE co.company_id = co2.company_id
ORDER BY co.company_id
FOR XML PATH ('')
), 2, 1000) [control_number]
The result I'm getting is including a leading comma: (', '0045', '4343').
I've used the STUFF function in the past to remove this but I can't figure out how to use it here. I keep getting errors like "STUFF function requires 4 values." Does anyone know how to remove that leading quote and comma?
You just need to add the quotes separately with STUFF in the query:
set #Control_Number =
(SELECT DISTINCT
STUFF(
(
SELECT ', '+ '''' + co.control_number + '''' AS [text()]
FROM #AGBCaseCompanyMap2 co
WHERE co.company_id = co2.company_id
ORDER BY co.company_id
FOR XML PATH ('')
), 1, 2, '') [control_number]

How to reduce execution time of SQL Select Query

TitemName and TshotName is the problem here
SELECT DISTINCT
tJobs.* ,
tCustomer.Name AS Customer_name ,
(SELECT tEmployee.First + ' ' + tEmployee.Last
FROM tEmployee
WHERE tEmployee.EmployeeID = tJobs.AccountExecutiveID) AS AccountExecutive,
(SELECT tEmployee.First + ' ' + tEmployee.Last
FROM tEmployee
WHERE tEmployee.EmployeeID = tJobs.AccountManagerID) AS AccountManager,
dbo.RetrunUserFavourite(tJobs.JobNumber, 33369, 'Employee') AS Favorites,
(SELECT COUNT(*)
FROM tShots
WHERE tShots.JobNumber = tJobs.JobNumber) AS shotcount,
SUBSTRING((SELECT ', ' + SKU + ', ' + Source + ', ' + ModelNumber
+ ', ' + Description
FROM tItems
WHERE tItems.CustomerID = tCustomer.CustomerID
FOR XML PATH('')), 3, 200000) titemName,
SUBSTRING((SELECT ', ' + ArtDirection + ', '
+ REPLACE(CONVERT(VARCHAR(5), AdDate, 110), '-',
'/')
FROM tShots
WHERE tShots.JobNumber = tJobs.JobNumber
FOR XML PATH('')), 3, 200000) TshotName
FROM
tJobs
INNER JOIN
tCustomer ON tCustomer.CustomerID = tJobs.CustomerID
WHERE
tCustomer.CustomerID = 68666
I strongly agree with M Ali's comments. Two points I would make. The first is not with regard to performance. But, instead of substring() use:
STUFF((SELECT ', ' + SKU + ', ' + Source + ', ' + ModelNumber+ ', ' + Description
FROM tItems
WHERE tItems.CustomerID = tCustomer.CustomerID
FOR XML PATH('')
), 1, 1, '') as titemName
That way, you don't need strange, meaningless numbers floating around the code.
Second, you may need indexes. Based on the highlighted performance problems, I would suggest:
tItems(CustomerID)
and:
tshots(JobNumber, ArtDirection, AdDate)
You have awful lot of string manipulation going on is your query, anyway a slightly improved version of your query would look something like...
Select DISTINCT
tJobs.*
, tCustomer.Name AS Customer_name
, AE.First + ' ' + AE.Last AS AccountExecutive
, AM.First + ' ' + AM.Last AS AccountManager
, dbo.RetrunUserFavourite(tJobs.JobNumber,33369,'Employee')AS Favorites
, TS.shotcount
, SUBSTRING(( SELECT ', ' + SKU + ', ' + Source + ', ' + ModelNumber+ ', ' + Description
FROM tItems
where tItems.CustomerID=tCustomer.CustomerID
FOR XML PATH('')), 3, 200000)titemName
, SUBSTRING(( SELECT ', ' + ArtDirection +', '+REPLACE(CONVERT(VARCHAR(5),AdDate,110), '-','/')
FROM tShots
where tShots.JobNumber=tJobs.JobNumber
FOR XML PATH('')), 3, 200000)TshotName
From tJobs
inner join tCustomer on tCustomer.CustomerID = tJobs.CustomerID
Left join tEmployee AE ON AE.EmployeeID = tJobs.AccountExecutiveID
Left join tEmployee AM ON AM.EmployeeID = tJobs.AccountManagerID
Left join (
SELECT JobNumber , Count(*) shotcount
FROM tShots
GROUP BY JobNumber
) TS ON TS.JobNumber = tJobs.JobNumber
WHERE tCustomer.CustomerID = 68666
A Couple of Pointers:
Having sub-queries in your select statement makes it very inefficient, because the sub-query is executed for each row returned by the outer query, a more sensible way of doing it would be to use joins.
You Also have a call to a User-Defined Scalar function dbo.RetrunUserFavourite() in your select , these scalar UDFs are also performance killers, again the same execution logic is applied here, they are also executed for each row returned by the outer query, a more sensible way would be to put the function logic/code inside a CTE and join your query to that CTE.
These comma delimited lists that you are creating on the fly for last two columns will be slow, maybe an Inline-Table-Valued function can give better performance here.

Add selected values from multi column into one column separated by ','

I want to select values from multiple columns into one column. I have 2 separate columns from which i want to get name,address,state,zip in following format in SQL Server 2008
Name (new line)
address,state,zip
Name (new line)
address,state,zip
Query:
select
name + char(13) + concat(address,',', state,',', zip)
from
tbl1
join
tbl2 on....
I am not able to get the desired output. I get concat is not a recognized built in function name.
You could use + operator and cast the zip field as varchar directly like this:
For example:
select 'Dara Singh' + char(13) + '1234 Main Street' + ',' + 'NY' + ','
+ cast(95825 as varchar(10))
This is how your query would look:
select name + char(13) + [address] + ',' + [state] + ',' + cast([zip] as varchar(10))
from tbl1 join tbl2 on....

Concatenation of strings by for xml path

Hi!
Today I learned for xml path technique to concatenate strings in mssql. Since I've never worked with xml in mssql and google hasn't helped, I need to ask you.
Let's imagine the default case. We need to concatenate some strings from a table:
declare #xmlRepNames xml = (
select
', [' + report_name + ']'
from (
select distinct
report_order,
report_name
from #report
) x
order by
report_order
for xml path(''), type)
select
stuff((select #xmlRepNames.value('.', 'nvarchar(max)')), 1, 1, '')
So I get smth like this:
[str1], [str2], [strn]
Ok. It works fine. But I have two very similar concatenate blocks. The difference is just in the way the result string looks like:
[str1], [str2], [strn]
and
isnull([str1], 0) as [str1], isnull([str2], 0) as [str2], isnull([strn], 0) as [strn]
So I can write 2 very similar code blocks (already done, btw) with different string constructors or to try extend previous code to has xml variable containing 2 kind of constructors and then concatenate by xml node type. Doing 2nd way I met some problems - I wrote this:
declare #xmlRepNames xml = (
select
', [' + report_name + ']' as name,
', isnull([' + report_name + '], 0) as [' + report_name + ']' as res
from (
select distinct
report_order,
report_name
from #report
) x
order by
report_order
for xml path(''), type)
select
stuff((select #xmlRepNames.value('/name', 'nvarchar(max)')), 1, 1, ''),
stuff((select #xmlRepNames.value('/res', 'nvarchar(max)')), 1, 1, '')
but it raise error "XQuery [value()]: 'value()' requires a singleton (or empty sequence), found operand of type 'xdt:untypedAtomic *'".
To replace, e.g., '/name' to '/name[1]' or any other '/name[x]', will return just x-th 'name' record but not all 'name' records concatenated.
[question]: is it possible to solve problem 2nd way like I want and if it's possible then how?
[disclaimer]: the problem isn't really serious for me now (1st way just a little bit uglier but also fine), but it seems very interesting how to come over :)
Thanks!
Your subquery cannot return two values. If you just want to concatenate strings, you do not need the xml data type at all. You can do the stuff() and subquery in a single statement:
declare #Rep1Names nvarchar(max) = (
stuff((select ', [' + report_name + ']' as name
from (select distinct report_order, report_name
from #report
) x
order by report_order
for xml path('')
)
), 1, 1, '');
declare #Rep2Names nvarchar(max) = (
stuff(select ', isnull([' + report_name + '], 0) as [' + report_name + ']' as res
from (select distinct report_order, report_name
from #report
) x
order by report_order
for xml path('')
)
), 1, 1, '');
Ok, so I haven't been completely satisfied the way Gordon Linoff suggested and since I've found this kind of problem actual for me I'm adding here another solution without using for xml path:
declare
#pivot_sequence nvarchar(max),
#columns_sequence nvarchar(max)
select
#pivot_sequence = coalesce(#pivot_sequence + ', [', '[')
+ col_name + ']',
#columns_sequence = coalesce(#columns_sequence + ', ', '')
+ 'isnull([' + col_name + '], 0) as [' + col_name + ']'
from some_table
order by
/* some_columns if needed to order concatenation */
Obviously, it'll work much slower but in cases when you haven't many rows it won't drastically affect on performance. In my case I have dynamic pivot query and these strings are built for it - I won't have many columns in pivot so it's fine for me.

SQL Query to List

I have a table variable in a stored procedure. What I want is to find all of the unique values in one column and join them in a comma-separated list. I am already in a stored procedure, so I can do it some way that way; however, I am curious if I can do this with a query. I am on SQL Server 2008. This query gets me the values I want:
SELECT DISTINCT faultType FROM #simFaults;
Is there a way (using CONCAT or something like that) where I can get the list as a single comma-separated value?
This worked for me on a test dataset.
DECLARE #MyCSV Varchar(200) = ''
SELECT #MyCSV = #MyCSV +
CAST(faulttype AS Varchar) + ','
FROM #Simfaults
GROUP BY faultType
SET #MyCSV = LEFT(#MyCSV, LEN(#MyCSV) - 1)
SELECT #MyCSV
The last part is needed to trim the trailing comma.
+1 to JNK - the other common way you will see, which doesn't require a variable is:
SELECT DISTINCT faulttype + ','
FROM #simfaults
FOR XML PATH ('')
Note that if faulttype contains characters like "<" for example, those will be xml encoded. But for simple values this will be OK.
this is how we do this
create table #test (item int)
insert into #test
values(1),(2),(3)
select STUFF((SELECT ', ' + cast(Item as nvarchar)
FROM #test
FOR XML PATH('')), 1, 2, '')
Without the space after the comma it would be;
select STUFF((SELECT ',' + cast(Item as nvarchar)
FROM #test
FOR XML PATH('')), 1,1, '')