How to put a comma separated value from a column in a table into SQL IN operator? - sql

I have a table which has a column in which I am storing a comma separated text with single quotes for each of the comma separated values. These values are employee IDs. This is how it looks
Now, I have a SQL query wherein I need to put the value from this column into a SQL IN operator. Something like this:
select *
from EMPLOYEE_MASTER
where EMPLOYEEID IN (select CM_CONFIG_VALUE
from ADL_CONFIG_MAST_T
where CM_CONFIG_KEY like 'ATT_BIOMETRIC_OU_ID'
)
But this, does not work, the query when executed returns 0 rows whereas if I execute the query normally like below, it works.
select *
from EMPLOYEE_MASTER
where EMPLOYEEID IN('9F3DD4B791554DDE','C9B90D62851D43AB','828CB9E6204B4DDC')
Please suggest what I should do here. I have tried using substring to remove the first and the last character as well assuming that single quotes might be the issue, but that does not work either.

select * from EMPLOYEE_MASTER where EMPLOYEEID IN(select EMPLOYEEID from ADL_CONFIG_MAST_T where CM_CONFIG_KEY like 'ATT_BIOMETRIC_OU_ID')
column should be same in where COLUMNNAME IN (select COLUMNNMAE from tablename)

You can create a temp varible and then use exec command to get the desired result.
declare #temp varchar(200)
select #temp=CM_CONFIG_VALUE
from ADL_CONFIG_MAST_T
where CM_CONFIG_KEY like 'ATT_BIOMETRIC_OU_ID'
exec('select *
from EMPLOYEE_MASTER
where EMPLOYEEID IN (' + #temp + ')')

Try This:
DECLARE #ID VARCHAR(500);
DECLARE #Number VARCHAR(500);
DECLARE #comma CHAR;
SET #comma = ','
SET #ID = (select CM_CONFIG_VALUE
from ADL_CONFIG_MAST_T
where CM_CONFIG_KEY like %ATT_BIOMETRIC_OU_ID% + #comma);
Create table #temp (EMPLOYEEID varchar(500))
WHILE CHARINDEX(#comma, #ID) > 0
BEGIN
SET #Number = SUBSTRING(#ID, 0, CHARINDEX(#comma, #ID))
SET #ID = SUBSTRING(#ID, CHARINDEX(#comma, #ID) + 1, LEN(#ID))
Insert into #temp
select #Number
END
select *
from EMPLOYEE_MASTER
where EMPLOYEEID IN(select EMPLOYEEID from #temp)

The reason you are not getting it in your query is because your inner query returns only one row. So your query searches for '9F3DD4B791554DDE','C9B90D62851D43AB','828CB9E6204B4DDC' as as single record.
If your compatibility level is greater than or equal to 130 you can use STRING_SPLIT() function. Then your query would be
SELECT *
FROM EMPLOYEE_MASTER
WHERE EMPLOYEEID IN
(SELECT value AS empid
FROM ADL_CONFIG_MAST_T CROSS APPLY string_split(CM_CONFIG_VALUE, ',' )
WHERE CM_CONFIG_KEY LIKE 'ATT_BIOMETRIC_OU_ID' )
What this actually does is, it splits the CM_CONFIG_VALUE with ',' and returns them as rows. This is the value column I have referred. Then you use them with the IN clause.
Hope this helps!

Direct IN condition will not work here. You have split your string before searching. You can do that with XML options in SQL SERVER 2014
SELECT *
FROM EMP
WHERE EMPID IN (
SELECT a.c.value('.', 'VARCHAR(1000)')
FROM (
SELECT x = CAST('<a>' +
REPLACE(REPLACE(CM_CONFIG_VALUE , ',', '</a><a>'),'''','') + '</a>' AS XML )
FROM ADL_CONFIG_MAST_T
-- WHERE <your_condition>
) m
CROSS APPLY x.nodes('/a') a(c))
CHECK DEMO HERE
For the version 2016 and above you can use STRING_SPLIT with Compatibility level 130

Related

query not retrieving values returned from split string

I generate comma seperated string and add single quite to each numbers
Here is how i do it
DECLARE #IDs NVARCHAR(max)
SELECT #IDs = COALESCE(#IDs +',', '') + ''''
+ Cast([mynos] AS NVARCHAR(255)) + ''''
FROM mytable
WHERE id = 22
If i print variable #IDs then i get below output
'78888','3333','1222'
When i use same variable in this query then query doesnt return any value
SELECT *
FROM table1
WHERE ids IN ( #IDs )
How to fix this?
It doesn't work as your query is effectively doing this:
SELECT *
FROM TABLE
WHERE Ids IN ('''78888'',''3333',''1222''');
Which would also be equivalent to:
SELECT *
FROM TABLE
WHERE Ids = '''78888'',''3333',''1222''';
If you want to do the query as you have done, you'll need to split your delomited data out again. As you're using SQL Server 2012, you can't make use of STRING_SPLIT, so you'll need to a different one; such as Jeff Moden's DelimitedSplit8K. Then you can do:
SELECT *
FROM TABLE
WHERE IDs IN (SELECT items
FROM dbo.DelimitedSplit8K (#IDs,','));
However, why are you not simply doing...
SELECT *
FROM TABLE T
WHERE EXISTS (SELECT 1
FROM myTable mT
WHERE mT.Id = 22
AND mT.myNos = T.Ids);
You can use dynamic query #id is string variable not multi-value argument
DECLARE #IDs nVARCHAR(MAX)
SELECT #IDs = COALESCE(#IDs +',' ,'') + '''' + CAST([myNos] AS nVARCHAR(255)) + ''''
FROM myTable WHERE Id = 22
DECLARE #query nVARCHAR(MAX)
SET #query = "Select * from table1 where Ids in ("+#IDs+")"
EXECUTE sp_executesql #query
I tried below and it worked
select * from table1 where id in (select mynos from mytable where id = 22)
Thanks to #Larnu for giving me idea

Can we use LIKE in subquery instead of IN

I am using following sql query
SELECT * FROM TestTable WHERE keyword IN ( Select Tags from Tags)
keyword in table are stored as keyword1, keyword2, keyword3
If it was single keyword the above query works fine but i have multiple keywords and i need to search each one of them in the
I dont thing above query is giving me right result as i am comparing
keyword1, keyword2, keyword3 with IN (keyword1, keyword2, keyword3) which wont match i tried o use instead
SELECT * FROM TestTable WHERE keyword LIKE ( Select Tags from Tags)
But it generates error
Subquery returned more than 1 value. This is not permitted when the
subquery follows =, !=, <, <= , >, >= or when the subquery is used as
an expression. The statement has been terminated.
can can i make it work so it loops through each keyword in table1, Table2 is tempTable and has these keyword1, keyword2, keyword3 in three rows
SQL FIDDLE
Fiddle is with sample data
You can do like following if you want to use pattern match.
Using EXISTS
SELECT * FROM TABLE1 T1
WHERE EXISTS
(
SELECT 1 FROM TABLE2 T2 WHERE T1.Keyword LIKE '%' + T2.keyword + '%'
)
Using JOIN
SELECT * FROM TABLE1 T1
INNER JOIN TABLE2 T2 ON T1.Keyword LIKE '%' + T2.keyword + '%'
If it is exact match, you ca do like following.
SELECT * FROM TABLE1 T1
INNER JOIN TABLE2 T2 ON T1.Keyword = T2.keyword
About your error:
Your subquery gives you multiple results and the LIKE operator cant compare more then 1 to 1. The IN operator was a good idea, but
If you are looking for something in table2 that matches EXACTLY a record (or more) in table1 this is your target:
SELECT *
FROM TABLE1
INNER JOIN TABLE2 ON TABLE2.keyword = TABLE1.keyword
If you are looking for anything in table2 that is SIMILAR to one or more records to the table1 use this:
SELECT *
FROM TABLE1
INNER JOIN TABLE2 ON TABLE2.keyword+'%' LIKE TABLE1.keyword
if you are on sql server or +, use string_split function, else :
create function split:
CREATE FUNCTION [dbo].[fn_split](
#str VARCHAR(MAX),
#delimiter CHAR(1)
)
RETURNS #returnTable TABLE (idx INT PRIMARY KEY IDENTITY, item VARCHAR(8000))
AS
BEGIN
DECLARE #pos INT
SELECT #str = #str + #delimiter
WHILE LEN(#str) > 0
BEGIN
SELECT #pos = CHARINDEX(#delimiter,#str)
IF #pos = 1
INSERT #returnTable (item)
VALUES (NULL)
ELSE
INSERT #returnTable (item)
VALUES (rtrim(ltrim(SUBSTRING(#str, 1, #pos-1))))
SELECT #str = SUBSTRING(#str, #pos+1, LEN(#str)-#pos)
END
RETURN
END
Split your values like it:
select * from tmp20180308 t1 CROSS APPLY fn_split(t1.keyword, ',') t2
inner join table2 t3 on t3.keyword=t2.item
and do your joins with other table
It can be done using Dynamic SQL. Check different methods for the one that has performance advantage:
SQLFiddle:
Declare #keywords as nvarchar(max)
Declare #Sql as nvarchar(max)
select #keywords =
stuff((
select distinct ' or [Tags] like ''%' + [tags] + '%'''
from [tags]
for xml path('')
),1,3,'')
set #Sql = 'SELECT * FROM [TestTable] WHERE ' + #keywords
exec(#Sql)
Not Fiddle:
create table a (keyword varchar(20))
create table b (keyword varchar(20))
insert into a values ('the'), ( 'quick'), ( 'brown'), ( 'fox'), ( 'jumped'), ( 'over'), ( 'the'), ( 'lazy'), ( 'dog')
insert into b values ('the'), ( 'quic'), ( 'browns'), ( 'x'), ( 'jumped'), ('quick,brown,fox')
Declare #keywords as nvarchar(max)
Declare #Sql as nvarchar(max)
select #keywords =
stuff((
select distinct ' or keyword like ''%' + [keyword] + '%'''
--select distinct ' or keyword = ''' + [keyword] + '''' --if exact match is required
from b
for xml path('')
),1,3,'')
set #Sql = 'SELECT * FROM a WHERE ' + #keywords
exec(#Sql)

Optimal way to concatenate/aggregate strings

I'm finding a way to aggregate strings from different rows into a single row. I'm looking to do this in many different places, so having a function to facilitate this would be nice. I've tried solutions using COALESCE and FOR XML, but they just don't cut it for me.
String aggregation would do something like this:
id | Name Result: id | Names
-- - ---- -- - -----
1 | Matt 1 | Matt, Rocks
1 | Rocks 2 | Stylus
2 | Stylus
I've taken a look at CLR-defined aggregate functions as a replacement for COALESCE and FOR XML, but apparently SQL Azure does not support CLR-defined stuff, which is a pain for me because I know being able to use it would solve a whole lot of problems for me.
Is there any possible workaround, or similarly optimal method (which might not be as optimal as CLR, but hey I'll take what I can get) that I can use to aggregate my stuff?
SOLUTION
The definition of optimal can vary, but here's how to concatenate strings from different rows using regular Transact SQL, which should work fine in Azure.
;WITH Partitioned AS
(
SELECT
ID,
Name,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Name) AS NameNumber,
COUNT(*) OVER (PARTITION BY ID) AS NameCount
FROM dbo.SourceTable
),
Concatenated AS
(
SELECT
ID,
CAST(Name AS nvarchar) AS FullName,
Name,
NameNumber,
NameCount
FROM Partitioned
WHERE NameNumber = 1
UNION ALL
SELECT
P.ID,
CAST(C.FullName + ', ' + P.Name AS nvarchar),
P.Name,
P.NameNumber,
P.NameCount
FROM Partitioned AS P
INNER JOIN Concatenated AS C
ON P.ID = C.ID
AND P.NameNumber = C.NameNumber + 1
)
SELECT
ID,
FullName
FROM Concatenated
WHERE NameNumber = NameCount
EXPLANATION
The approach boils down to three steps:
Number the rows using OVER and PARTITION grouping and ordering them as needed for the concatenation. The result is Partitioned CTE. We keep counts of rows in each partition to filter the results later.
Using recursive CTE (Concatenated) iterate through the row numbers (NameNumber column) adding Name values to FullName column.
Filter out all results but the ones with the highest NameNumber.
Please keep in mind that in order to make this query predictable one has to define both grouping (for example, in your scenario rows with the same ID are concatenated) and sorting (I assumed that you simply sort the string alphabetically before concatenation).
I've quickly tested the solution on SQL Server 2012 with the following data:
INSERT dbo.SourceTable (ID, Name)
VALUES
(1, 'Matt'),
(1, 'Rocks'),
(2, 'Stylus'),
(3, 'Foo'),
(3, 'Bar'),
(3, 'Baz')
The query result:
ID FullName
----------- ------------------------------
2 Stylus
3 Bar, Baz, Foo
1 Matt, Rocks
Are methods using FOR XML PATH like below really that slow? Itzik Ben-Gan writes that this method has good performance in his T-SQL Querying book (Mr. Ben-Gan is a trustworthy source, in my view).
create table #t (id int, name varchar(20))
insert into #t
values (1, 'Matt'), (1, 'Rocks'), (2, 'Stylus')
select id
,Names = stuff((select ', ' + name as [text()]
from #t xt
where xt.id = t.id
for xml path('')), 1, 2, '')
from #t t
group by id
STRING_AGG() in SQL Server 2017, Azure SQL, and PostgreSQL:
https://www.postgresql.org/docs/current/static/functions-aggregate.html
https://learn.microsoft.com/en-us/sql/t-sql/functions/string-agg-transact-sql
GROUP_CONCAT() in MySQL
http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html#function_group-concat
(Thanks to #Brianjorden and #milanio for Azure update)
Example Code:
select Id
, STRING_AGG(Name, ', ') Names
from Demo
group by Id
SQL Fiddle: http://sqlfiddle.com/#!18/89251/1
Although #serge answer is correct but i compared time consumption of his way against xmlpath and i found the xmlpath is so faster. I'll write the compare code and you can check it by yourself.
This is #serge way:
DECLARE #startTime datetime2;
DECLARE #endTime datetime2;
DECLARE #counter INT;
SET #counter = 1;
set nocount on;
declare #YourTable table (ID int, Name nvarchar(50))
WHILE #counter < 1000
BEGIN
insert into #YourTable VALUES (ROUND(#counter/10,0), CONVERT(NVARCHAR(50), #counter) + 'CC')
SET #counter = #counter + 1;
END
SET #startTime = GETDATE()
;WITH Partitioned AS
(
SELECT
ID,
Name,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Name) AS NameNumber,
COUNT(*) OVER (PARTITION BY ID) AS NameCount
FROM #YourTable
),
Concatenated AS
(
SELECT ID, CAST(Name AS nvarchar) AS FullName, Name, NameNumber, NameCount FROM Partitioned WHERE NameNumber = 1
UNION ALL
SELECT
P.ID, CAST(C.FullName + ', ' + P.Name AS nvarchar), P.Name, P.NameNumber, P.NameCount
FROM Partitioned AS P
INNER JOIN Concatenated AS C ON P.ID = C.ID AND P.NameNumber = C.NameNumber + 1
)
SELECT
ID,
FullName
FROM Concatenated
WHERE NameNumber = NameCount
SET #endTime = GETDATE();
SELECT DATEDIFF(millisecond,#startTime, #endTime)
--Take about 54 milliseconds
And this is xmlpath way:
DECLARE #startTime datetime2;
DECLARE #endTime datetime2;
DECLARE #counter INT;
SET #counter = 1;
set nocount on;
declare #YourTable table (RowID int, HeaderValue int, ChildValue varchar(5))
WHILE #counter < 1000
BEGIN
insert into #YourTable VALUES (#counter, ROUND(#counter/10,0), CONVERT(NVARCHAR(50), #counter) + 'CC')
SET #counter = #counter + 1;
END
SET #startTime = GETDATE();
set nocount off
SELECT
t1.HeaderValue
,STUFF(
(SELECT
', ' + t2.ChildValue
FROM #YourTable t2
WHERE t1.HeaderValue=t2.HeaderValue
ORDER BY t2.ChildValue
FOR XML PATH(''), TYPE
).value('.','varchar(max)')
,1,2, ''
) AS ChildValues
FROM #YourTable t1
GROUP BY t1.HeaderValue
SET #endTime = GETDATE();
SELECT DATEDIFF(millisecond,#startTime, #endTime)
--Take about 4 milliseconds
Update: Ms SQL Server 2017+, Azure SQL Database
You can use: STRING_AGG.
Usage is pretty simple for OP's request:
SELECT id, STRING_AGG(name, ', ') AS names
FROM some_table
GROUP BY id
Read More
Well my old non-answer got rightfully deleted (left in-tact below), but if anyone happens to land here in the future, there is good news. They have implimented STRING_AGG() in Azure SQL Database as well. That should provide the exact functionality originally requested in this post with native and built in support. #hrobky mentioned this previously as a SQL Server 2016 feature at the time.
--- Old Post:
Not enough reputation here to reply to #hrobky directly, but STRING_AGG looks great, however it is only available in SQL Server 2016 vNext currently. Hopefully it will follow to Azure SQL Datababse soon as well..
You can use += to concatenate strings, for example:
declare #test nvarchar(max)
set #test = ''
select #test += name from names
if you select #test, it will give you all names concatenated
I found Serge's answer to be very promising, but I also encountered performance issues with it as-written. However, when I restructured it to use temporary tables and not include double CTE tables, the performance went from 1 minute 40 seconds to sub-second for 1000 combined records. Here it is for anyone who needs to do this without FOR XML on older versions of SQL Server:
DECLARE #STRUCTURED_VALUES TABLE (
ID INT
,VALUE VARCHAR(MAX) NULL
,VALUENUMBER BIGINT
,VALUECOUNT INT
);
INSERT INTO #STRUCTURED_VALUES
SELECT ID
,VALUE
,ROW_NUMBER() OVER (PARTITION BY ID ORDER BY VALUE) AS VALUENUMBER
,COUNT(*) OVER (PARTITION BY ID) AS VALUECOUNT
FROM RAW_VALUES_TABLE;
WITH CTE AS (
SELECT SV.ID
,SV.VALUE
,SV.VALUENUMBER
,SV.VALUECOUNT
FROM #STRUCTURED_VALUES SV
WHERE VALUENUMBER = 1
UNION ALL
SELECT SV.ID
,CTE.VALUE + ' ' + SV.VALUE AS VALUE
,SV.VALUENUMBER
,SV.VALUECOUNT
FROM #STRUCTURED_VALUES SV
JOIN CTE
ON SV.ID = CTE.ID
AND SV.VALUENUMBER = CTE.VALUENUMBER + 1
)
SELECT ID
,VALUE
FROM CTE
WHERE VALUENUMBER = VALUECOUNT
ORDER BY ID
;
Try this, i use it in my projects
DECLARE #MetricsList NVARCHAR(MAX);
SELECT #MetricsList = COALESCE(#MetricsList + '|', '') + QMetricName
FROM #Questions;

Combination of 'LIKE' and 'IN' using t-sql

How can I do this kind of selection:
SELECT *
FROM Street
WHERE StreetName LIKE IN ('% Main Street', 'foo %')
Please don't tell me that I can use OR because these actually comes from a query.
There is no combined LIKE and IN syntax but you can use LIKE to JOIN onto your query as below.
;WITH Query(Result) As
(
SELECT '% Main Street' UNION ALL
SELECT 'foo %'
)
SELECT DISTINCT s.*
FROM Street s
JOIN Query q ON StreetName LIKE q.Result
Or to use your example in the comments
SELECT DISTINCT s.*
FROM Street s
JOIN CarStreets cs ON s.StreetName LIKE cs.name + '%'
WHERE cs.Streets = 'offroad'
You don't have a lot of choices here.
SELECT * FROM Street Where StreetName LIKE '% Main Street' OR StreetName LIKE 'foo %'
If this is part of an existing, more complicated query (which is the impression I'm getting), you could create a table value function that does the checking for you.
SELECT * FROM Street Where StreetName IN (dbo.FindStreetNameFunction('% Main Street|foo %'))
I'd recommend using the simplest solution (the first). If this is nested inside a larger, more complicated query, post it and we'll take a look.
I had a similar conundrum but due to only needing to match the start of a string, I changed my 'like' to SUBSTRING as such:
SELECT *
FROM codes
WHERE SUBSTRING(code, 1, 12) IN ('012316963429', '012315667849')
You can resort to Dynamic SQL and wrapping up all in a stored procedure.
If you get the LIKE IN param in a string as tokens with a certain separator, like
'% Main Street,foo %,Another%Street'
first you need to create a function that receives a list of LIKE "tokens" and returns a table of them.
CREATE FUNCTION [dbo].[SplitList]
(
#list nvarchar(MAX),
#delim nvarchar(5)
)
RETURNS #splitTable table
(
value nvarchar(50)
)
AS BEGIN
While (Charindex(#delim, #list)>0) Begin
Insert Into #splitTable (value)
Select ltrim(rtrim(Substring(#list, 1, Charindex(#delim, #list)-1)))
Set #list = Substring(#list, Charindex(#delim, #list)+len(#delim), len(#list))
End
Insert Into #splitTable (value) Select ltrim(rtrim(#list))
Return
END
Then in the SP you have the following code
declare
#sql nvarchar(MAX),
#subWhere nvarchar(MAX)
#params nvarchar(MAX)
-- prepare the where sub-clause to cover LIKE IN (...)
-- it will actually generate where sub clause StreetName Like option1 or StreetName Like option2 or ...
set #subWhere = STUFF(
(
--(**)
SELECT ' OR StreetName like ''' + value + '''' FROM SplitList('% Main Street,foo %,Another%Street', ',')
FOR XML PATH('')
), 1, 4, '')
-- create the dynamic SQL
set #sql ='select * from [Street]
where
(' + #subWhere + ')
-- and any additional query params here, if needed, like
AND StreetMinHouseNumber = #minHouseNumber
AND StreetNumberOfHouses between (#minNumberOfHouses and #maxNumberOfHouses)'
set #params = ' #minHouseNumber nvarchar(5),
#minNumberOfHouses int,
#minNumberOfHouses int'
EXECUTE sp_executesql #sql, #params,
#minHouseNumber,
#minNumberOfHouses,
#minNumberOfHouses
Of course, if you have your LIKE IN parameters in another table or you gather it through a query, you can replace that in line (**)
I believe I can clarify what he is looking for, but I don't know the answer. I'll use my situation to demonstrate. I have a table with a column called "Query" that holds SQL queries. These queries sometimes contain table names from one of my databases. I need to find all Query rows that contain table names from a particular database. So, I can use the following code to get the table names:
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
I'm trying to use a WHERE IN clause to identify the Query rows that contain the table names I'm interested in:
SELECT *
FROM [DatasourceQuery]
WHERE Query IN LIKE
(
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
)
I believe the OP is trying to do something like that.
This is my way:
First create a table function:
create function [splitDelimeter](#str nvarchar(max), #delimeter nvarchar(10)='*')
returns #r table(val nvarchar(max))
as
begin
declare #x nvarchar(max)=#str
set #x='<m>'+replace(#x, #delimeter, '</m><m>')+'</m>'
declare #xx xml=cast(#x as xml)
insert #r(val)
SELECT Tbl.Col.value('.', 'nvarchar(max)') id
FROM #xx.nodes('/m') Tbl(Col)
return
end
Then split the search text with your preference delimeter. After that you can do your select with left join as below:
declare #s nvarchar(max)='% Main Street*foo %'
select a.* from street a
left join gen.splitDelimeter(#s, '*') b
on a.streetname like b.val
where val is not null
What I did when solving a similar problem was:
SELECT DISTINCT S.*
FROM Street AS S
JOIN (SELECT value FROM String_Split('% Main Street,foo %', N',')) T
ON S.StreetName LIKE T.value;
Which is functionally similar to Martin's answer but a more direct answer to the question.
Note: DISTINCT is used because you might get multiple matches for a single row.

How to return multiple values in one column (T-SQL)?

I have a table UserAliases (UserId, Alias) with multiple aliases per user. I need to query it and return all aliases for a given user, the trick is to return them all in one column.
Example:
UserId/Alias
1/MrX
1/MrY
1/MrA
2/Abc
2/Xyz
I want the query result in the following format:
UserId/Alias
1/ MrX, MrY, MrA
2/ Abc, Xyz
Thank you.
I'm using SQL Server 2005.
p.s. actual T-SQL query would be appreciated :)
You can use a function with COALESCE.
CREATE FUNCTION [dbo].[GetAliasesById]
(
#userID int
)
RETURNS varchar(max)
AS
BEGIN
declare #output varchar(max)
select #output = COALESCE(#output + ', ', '') + alias
from UserAliases
where userid = #userID
return #output
END
GO
SELECT UserID, dbo.GetAliasesByID(UserID)
FROM UserAliases
GROUP BY UserID
GO
Well... I see that an answer was already accepted... but I think you should see another solutions anyway:
/* EXAMPLE */
DECLARE #UserAliases TABLE(UserId INT , Alias VARCHAR(10))
INSERT INTO #UserAliases (UserId,Alias) SELECT 1,'MrX'
UNION ALL SELECT 1,'MrY' UNION ALL SELECT 1,'MrA'
UNION ALL SELECT 2,'Abc' UNION ALL SELECT 2,'Xyz'
/* QUERY */
;WITH tmp AS ( SELECT DISTINCT UserId FROM #UserAliases )
SELECT
LEFT(tmp.UserId, 10) +
'/ ' +
STUFF(
( SELECT ', '+Alias
FROM #UserAliases
WHERE UserId = tmp.UserId
FOR XML PATH('')
)
, 1, 2, ''
) AS [UserId/Alias]
FROM tmp
/* -- OUTPUT
UserId/Alias
1/ MrX, MrY, MrA
2/ Abc, Xyz
*/
DECLARE #Str varchar(500)
SELECT #Str=COALESCE(#Str,'') + CAST(ID as varchar(10)) + ','
FROM dbo.fcUser
SELECT #Str
group_concat() sounds like what you're looking for.
http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat
since you're on mssql, i just googled "group_concat mssql" and found a bunch of hits to recreate group_concat functionality. here's one of the hits i found:
http://www.stevenmapes.com/index.php?/archives/23-Recreating-MySQL-GROUP_CONCAT-In-MSSQL-Cross-Tab-Query.html
You can either loop through the rows with a cursor and append to a field in a temp table, or you could use the COALESCE function to concatenate the fields.
Sorry, read the question wrong the first time. You can do something like this:
declare #result varchar(max)
--must "initialize" result for this to work
select #result = ''
select #result = #result + alias
FROM aliases
WHERE username='Bob'