How can I pull a list of ID's from a SQL table as a comma-separated values string?
In addition to @OMG Ponies method, you could also try this COALESCE trick from:
Using COALESCE to Build Comma-Delimited Strings
declare @string nvarchar(255)
select @string = coalesce(@string + ', ', '') + cast(prodid as nvarchar(5))
from products
Convert Comma separated ids into its assigned values
For a table containing the languages like this:
CREATE TABLE languages (
id INTEGER,
name VARCHAR(20)
);
INSERT INTO languages
(id, name)
VALUES
('1', 'English'),
('2', 'Germany'),
('3', 'Spanish'),
('4', 'Hindi'),
('5', 'Arabic');
you can join the tables, group by StaffID and use string_agg()
:
select
t.StaffID,
string_agg(l.name, ',') within group (order by l.id) LanguagesSpoken
from tablename t inner join languages l
on concat(',', t.languagesspoken, ',') like concat('%,', l.id, ',%')
group by t.StaffID
See the demo.
Results:
> StaffID | LanguagesSpoken
> ------: | :----------------------
> 1 | English,Germany,Spanish
> 2 | Spanish,Hindi
> 3 | Germany,Arabic
How to convert list of comma separated Ids into their name?
WITH data AS (
SELECT * FROM (VALUES (1, '10,15'), (2, NULL)) x(id, task_ids)
),
task AS (
SELECT * FROM (VALUES ('10', 'a'), ('15', 'b')) x(id, task_name)
)
SELECT
d.id, d.task_ids
-- array_agg will obviously capture NULL task_name comping from LEFT JOIN, so we need to filter out such results
IF(array_agg(t.task_name) IS NOT DISTINCT FROM ARRAY[NULL], NULL, array_agg(t.task_name)) task_names
FROM data d
-- split task_ids by `,`, convert into numbers, UNNEST into separate rows
LEFT JOIN UNNEST (split(d.task_ids, ',')) AS e(task_id) ON true
-- LEFT JOIN with task to pull the task name
LEFT JOIN task t ON e.task_id = t.id
-- aggregate back
GROUP BY d.id, d.task_ids;
Multiple rows to one comma-separated value different ID
Test Data
DECLARE @Table1 TABLE(ID INT, Value INT)
INSERT INTO @Table1 VALUES (1,100),(1,200),(1,300),(1,400)
Query
SELECT ID
,STUFF((SELECT ', ' + CAST(Value AS VARCHAR(10)) [text()]
FROM @Table1
WHERE ID = t.ID
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,2,' ') List_Output
FROM @Table1 t
GROUP BY ID
Result Set
╔════╦═════════════════════╗
║ ID ║ List_Output ║
╠════╬═════════════════════╣
║ 1 ║ 100, 200, 300, 400 ║
╚════╩═════════════════════╝
EF SQL query Performance on comma-separated string Ids
If you store Ids as comma separated string - you always have TABLE/INDEX scan. If your table is small it can be enough.
With SecondaryTable
table which stores Ids associated with main table there a lot of other plans:
- You can leave as is and trust or not DB Engine optimiser
query = query.Where(x => x.SecondaryTable.Any(s => s.Id == value));
- If pair (MainId, Id) is unique. The following query should definitely hit index
var query =
from m in query
from s in m.SecondaryTable.Where(s => s.Id == value)
select s;
- If pair (MainId, Id) is NOT unique.
var secondary = db.SecondaryTable.Where(s => s.Id == value);
var mainIds = secondary.Select(s => new { s.MainId }).Distinct();
query =
from m in query
from s in mainIds.Where(s => s.MainId == m.Id)
select m;
Anyway, better to test and check execution plan.
Get comma-separated set of values from table where another reference value on another table appears twice (or more)
Nice starting fiddle, thanks! If we just take what you already have and put it in a CTE, we can write a standard string aggregation around it:
;WITH subs AS
(
SELECT prod.CODE, sub.SUBSTITUTECODE
FROM @SUBSTITUTE AS sub
INNER JOIN @MATERIAL AS prod ON prod.ID = sub.ITEID
WHERE sub.SUBSTITUTECODE IN (SELECT sub.SUBSTITUTECODE
FROM @SUBSTITUTE AS sub
INNER JOIN @MATERIAL AS prod ON prod.ID = sub.ITEID
GROUP BY sub.SUBSTITUTECODE
HAVING COUNT(sub.SUBSTITUTECODE) > 1)
)
SELECT CODES = STUFF((SELECT ',' + CODE
FROM subs AS s2 WHERE s2.SUBSTITUTECODE = subs.SUBSTITUTECODE
FOR XML PATH(''), TYPE).value(N'./text()[1]', N'nvarchar(max)'),1,1,''),
SUBSTITUTECODE FROM subs
GROUP BY SUBSTITUTECODE;
- Example db<>fiddle
But we can simplify this code slightly, most importantly to avoid referencing both tables twice, like this:
;WITH subs AS
(
SELECT s.ITEID, s.SUBSTITUTECODE, m.CODE,
c = COUNT(*) OVER (PARTITION BY s.SUBSTITUTECODE)
FROM @SUBSTITUTE AS s
INNER JOIN @MATERIAL AS m
ON m.ID = s.ITEID
)
SELECT CODES = STUFF((SELECT ',' + CODE
FROM subs AS s2 WHERE s2.SUBSTITUTECODE = subs.SUBSTITUTECODE
FOR XML PATH(''), TYPE).value(N'./text()[1]', N'nvarchar(max)'),1,1,''),
SUBSTITUTECODE
FROM subs
WHERE c > 1
GROUP BY SUBSTITUTECODE;
- Example db<>fiddle
Note that on more modern versions of SQL Server (2017+), STRING_AGG()
makes this much easier:
SELECT CODES = STRING_AGG(m.CODE, ','), s.SUBSTITUTECODE
FROM @SUBSTITUTE AS s
INNER JOIN @MATERIAL AS m
ON m.ID = s.ITEID
GROUP BY s.SUBSTITUTECODE
HAVING COUNT(*) > 1;
- Example db<>fiddle
How do I get a comma separated list of ten values and not all of them?
Use SUBSTRING_INDEX()
with 10
as the 3d argument:
SELECT SUBSTRING_INDEX(GROUP_CONCAT(n.id), ',', 10) FROM tbl_names n
Related Topics
Order by Column1 If Column1 Is Not Null, Otherwise Order by Column2
Passing C# Datatable as a Parameter to Stored Procedure in Ms SQL Server 2008
Is There a Tool to Generate a Full Database Ddl for SQL Server? What About Postgres and MySQL
Get The Type of a Variable in MySQL
What Is This Operand (*= Star-Equals) in SQL Server 2000
Order of Execution in SQL Server Variable Assignment Using Select
How to Have Temp Tables in a Function
Generated Excel from Ssis But Getting Quote in Every Column
Can You Use Auto-Increment in MySQL with Out It Being The Primary Key
Sql Server Reverse Order After Using Desc
Apex 5.0: Show a Progress Bar While Database Action Is Performed
Find Records from Previous X Days
Adding Extra Column to View, Which Is Not Present in Table
How to Join Two Unrelated Tables in Sql
Display All Data of All Tables
Oracle SQL Return True If Exists Question
MySQL to Get The Count of Rows That Fall on a Date for Each Day of a Month