Тим очень хороший ответ.
Вы должны нормализовать вашу базу данных. Это правильный способ решить эту проблему.
Для получения дополнительной информации читайте Действительно ли плохо хранить список с разделителями в столбце базы данных? , где вы увидите множество причин, по которым ответ на этот вопрос Абсолютно да!
Однако бывают случаи, когда вы просто не можете изменить структуру базы данных по ряду причин. Иногда изменения слишком дороги, иногда вы работаете со сторонней базой данных.
Какова бы ни была причина, я ответил здесь на множество вопросов (и в других местах), где структура базы данных должна быть изменена, но это не вариант.
Поэтому я дам вам ответ, который показывает, как вы можете получить желаемый результат без изменения структуры базы данных.
Сначала создайте и заполните примеры таблиц ( Пожалуйста, сохраните этот шаг в ваших будущих вопросах):
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');
Затем я использую общее табличное выражение для разбиения значений в столбце Markets
на строки.
Charindex
предназначен для сохранения первоначального порядка значений в результате. (Примечание: этот прием работает только в том случае, если значения уникальны в каждой строке).
Примечание. String_split поддерживается базой данных Azure, но требует уровень совместимости не менее 130
WITH CTE AS
(
SELECT Markets,
TRIM(Value) As Code,
CHARINDEX(Value, Markets) As Sort
FROM @T
CROSS APPLY STRING_SPLIT(Markets, '|')
)
Затем, используя string_agg
Я восстанавливаю строки, но на этот раз с их переводами.
string_agg
поддерживается базой данных Azure, но требуется уровень совместимости не менее 140 .
Примечание: left join
и isnull
предназначены для обработки случаев, когда есть значение, которое не может быть найдено в таблице кодов. В вашем реальном случае вы можете отказаться от этих значений - в этом случае измените left join
на inner join
и удалите 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
Результаты:
Markets Translated
AD | AE | AF Andorra | United Arab Emirates | Afghanistan
NZ | AU | AD N/A | N/A | Andorra
US | UK N/A | United Kingdom
Вы можете увидеть живое демо на db <> fiddle
Если ваш уровень совместимости меньше 140, вы можете использовать более старый трюк для агрегирования строк, используя for xml
.
Если ваш уровень совместимости меньше 130, вы можете использовать пользовательскую функцию для разбиения строки .