我有一个带有2列(代码,说明)的CountryCounts表,下面是一个示例:
code description
AD Andorra
AE United Arab Emirates
AF Afghanistan
我在一个包含以下字符串的视图中有一个名为Markets的列:
Markets (this is one column)
AD | AE | AF
US | UK
NZ | AU | AD
我需要编写一条select语句,该语句将从定界符(|)之间的CountryCodes表中的Market列中查找代码。例如:
AD | AE | AF ----> Andorra | United Arab Emirates | Afghanistan
US | UK ----> United States | United Kingdom
我知道可以通过将select包裹在大量的replace语句中来附加它,但是此表中有249个代码,编写和维护起来似乎效率极低。
我也研究了string_split函数,但是我的SQL Server版本不支持该函数:Microsoft SQL Azure(RTM)-12.0.2000.8
有人有什么建议吗?
答案 0 :(得分:0)
正如@Jens的注释正确指出的那样,将国家/地区代码存储为长度不同的竖线分隔字符串是不好的表设计。相反,最好为每个记录存储一个关系,如下所示:
ID | code
1 | AD
1 | AE
1 | AF
2 | US
2 | UK
3 | NZ
3 | AU
3 | AD
然后,如果要将每个ID
的市场转换为CSV列表,则可以尝试:
SELECT
m.ID,
STRING_AGG(cc.description, ',') WITHIN GROUP (ORDER BY m.ID) AS markets
FROM Markets m
INNER JOIN CountryCodes cc
ON m.code = cc.code
GROUP BY
m.ID;
答案 1 :(得分:0)
蒂姆的答案很好。
您应该规范化数据库。那是解决这个问题的正确方法。
有关更多信息,请阅读Is storing a delimited list in a database column really that bad?,您将在这里看到很多答案,为什么这个问题的答案是绝对是!
但是,由于许多原因,很多时候您根本无法更改数据库结构。有时,更改太昂贵了,有时您正在使用第三方数据库。
不管是什么原因,我在这里(以及其他地方)都回答过很多问题,这些地方应该更改数据库结构,但这不是一个选择。
因此,我将为您提供一个答案,说明如何在不更改数据库结构的情况下获得所需的输出。
首先,创建并填充示例表(请在您将来的问题中为我们保存此步骤):
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
可以保留结果中值的原始顺序。 (注意:仅当每行中的值都是唯一的时,此技巧才有效)。
注意:Azure数据库支持String_split,但要求兼容级别至少为 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,则可以使用用户定义的函数来split the string。