Tim's answer is very good.
You should normalize your database. That is the correct way to solve this problem.
For more information, read Is storing a delimited list in a database column really that bad?, where you will see a lot of reasons why the answer to this question is Absolutely yes!
However there are plenty of times when you simply can't change the database structure for any number of reasons. Sometimes, the change is too expensive, sometimes you are working with a 3rd party database.
Whatever the reason is, I've had answered plenty of questions here (and in other places as well) where the database structure should be changed but it's not an option.
Therefor, I'll give you an answer that shows how you can get your desired output without changing the database structure.
First, create and populate sample tables (Please save us this step in your future questions):
DECLARE @Codes AS TABLE
(
Code char(2),
Description varchar(100)
);
INSERT INTO @Codes (Code, Description) VALUES
('AD', 'Andorra'),
('AE', 'United Arab Emirates'),
('AF', 'Afghanistan'),
('UK', 'United Kingdom');
DECLARE @T AS TABLE
(
Markets varchar(100)
);
INSERT INTO @T (Markets) VALUES
('AD | AE | AF'),
('US | UK'),
('NZ | AU | AD');
Then, I'm using a common table expression to split the values in the Markets
column into rows.
The Charindex
is there to preserve the original order of the values in the result. (Note: this trick only works if the values are unique within each row).
Note: String_split is supported by Azure database but require compatibility level of at least 130
WITH CTE AS
(
SELECT Markets,
TRIM(Value) As Code,
CHARINDEX(Value, Markets) As Sort
FROM @T
CROSS APPLY STRING_SPLIT(Markets, '|')
)
Then, using string_agg
I'm reconstructing the rows, but this time with their translations.
string_agg
is supported by Azure database but require compatibility level of at least 140.
Note: The left join
and isnull
are to handle cases where there is a value that can't be found in the codes table. In your actual case you might want to discard these values - if that is the case, change the left join
to an inner join
and remove the isnull
.
SELECT Markets,
STRING_AGG(ISNULL(Description, 'N/A'), ' | ') WITHIN GROUP(ORDER BY Sort) As Translated
FROM CTE
LEFT JOIN @Codes C
ON CTE.Code = C.Code
GROUP BY Markets
Results:
Markets Translated
AD | AE | AF Andorra | United Arab Emirates | Afghanistan
NZ | AU | AD N/A | N/A | Andorra
US | UK N/A | United Kingdom
You can see a live demo on db<>fiddle
If your compatibility level is less than 140 you can use the older trick for string aggregation using for xml
.
If your compatibility level is less than 130 you can use a user defined function to split the string.