The first thing to point out is that if you stored your data in a normalised fashion then you would not have as much of an issue, the best way would be a separate one to many table, e.g.
CustomerValues
Cust_ID Value
-------------------
1 ct
1 ct
1 ct
1 dir
2 ct
2 ct
.....
Your query would then become something like:
--SAMPLE DATA
WITH Customers AS
( SELECT *
FROM (VALUES
(1, 'a', 'b'),
(2, 'c', 'a'),
(3, 'd', 'e')
) AS t (cust_id, firstname, lastname)
), CustomerValues AS
( SELECT *
FROM (VALUES
(1, 'ct'), (1, 'ct'), (1, 'ct'), (1, 'dir'),
(2, 'ct'), (2, 'ct'), (2, 'ct'), (2, 'ct'), (2, 'ct'), (2, 'ct'),
(3, 'ct'), (3, 'ct'), (3, 'ct'), (3, 'dir'), (3, 'st')
) AS t (cust_id, value)
)
-- SAMPLE DATA END
SELECT c.cust_id,
c.firstname,
c.lastname,
value = STUFF(CustomerValues.value('.', 'NVARCHAR(MAX)'), 1, 1, '')
FROM Customers AS c
CROSS APPLY
( SELECT DISTINCT ';' + value
FROM CustomerValues AS cv
WHERE cv.cust_id = c.cust_id
FOR XML PATH(''), TYPE
) AS cv (CustomerValues);
For more reading on how the rows are concatenated see Grouped Concatenation in SQL Server
Without your data in this format, you would need to perform some kind of split. For more see Split strings the right way – or the next best way
WITH Customers AS
( SELECT *
FROM (VALUES
(1, 'a', 'b', 'ct;ct;ct;dir'),
(2, 'c', 'a', 'ct;ct;ct;ct;ct;ct'),
(3, 'd', 'e', 'ct;ct;ct;dir;st')
) AS t (cust_id, firstname, lastname, value)
), Numbers (Number) AS
( SELECT ROW_NUMBER() OVER(ORDER BY N1.N)
FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS n1 (N)
CROSS JOIN (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS n2 (N)
CROSS JOIN (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS n3 (N)
), CustomerValues AS
( SELECT c.cust_id,
value = SUBSTRING(c.value, Number, CHARINDEX(';', c.value + ';', n.Number) - n.Number)
FROM Customers AS c
INNER JOIN Numbers AS n
ON N.Number <= CONVERT(INT, LEN(c.value))
AND SUBSTRING(';' + c.value, n.Number, 1) = ';'
)
SELECT c.cust_id,
c.firstname,
c.lastname,
value = STUFF(CustomerValues.value('.', 'NVARCHAR(MAX)'), 1, 1, '')
FROM Customers AS c
CROSS APPLY
( SELECT DISTINCT ';' + value
FROM CustomerValues AS cv
WHERE cv.cust_id = c.cust_id
FOR XML PATH(''), TYPE
) AS cv (CustomerValues);