如何以基于集合的方式解析逗号分隔值?

How to resolve comma separated values in a set based manner?

我有一个主 table,其中包含每个 ID 的逗号分隔代码:

create table main (id int, codes nvarchar(3))

id  codes
1   HIR, RES, NAS
2   TA1, WQ9, PLM

以及描述这些代码含义的查找 table:

create table lookup (code nvarchar(3), description nvarchar(100))

code  description
HIR   High Rise
NAS   Mobile Home
PLM   Proposed Attached
...

我想从主 table select 并将逗号分隔的代码列表替换为相应描述的逗号分隔列表:

id  codes
1   High Rise, Residential, Mobile Home

我想出了如何遍历每一行、分解 CSV、手动查询每一行、重新构建字符串并生成我想要的内容的方法。

但是,有没有一种方法可以以基于集合的方式(并且更快)做到这一点?

对于主要的 table,您将要进行交叉应用 STRING_SPLIT 然后您可以将其加入您的查找 table 并使用 stuff() 和 for xml

您可以在此处了解交叉应用 STRING_SPLIT(2016 春夏): Turning a Comma Separated string into individual rows(列出其他方法)

您可以在此处学习有关 xml 的内容: Convert multiple rows into one with comma as separator

因为你是 2016 年,一个选项是 string_split,但没有维护序列的 gtd。也许这会有所帮助

例子

Select A.ID
      ,Codes = B.S
 From  Main A
 Cross Apply (
                Select S = stuff((Select ', ' +[description] 
                                   From (
                                          Select RetSeq = Row_Number() over (Order By (Select null))
                                                ,RetVal = ltrim(rtrim(B.i.value('(./text())[1]', 'varchar(100)')))
                                           From  (Select x = Cast('<x>' + replace((Select replace(A.[codes],',','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A 
                                           Cross Apply x.nodes('x') AS B(i)
                                         ) B1
                                    Join Lookup B2 on B1.RetVal=B2.code
                                    Order by RetSeq
                                    For XML Path (''))
                                  ,1,2,'') 
             ) B

Returns

ID  Codes
1   High Rise, Mobile Home
2   Proposed Attached

注意项目丢失,因为查找不完整。

由于您可以使用 SQL Server 2017,所以 STRING_AGG():

select m.id, string_agg(l.description, ', ') within group (order by charindex(l.code, m.codes)) codes
from main m inner join lookup l
on concat(',', replace(m.codes, ', ', ','), ',') like concat('%', l.code, '%')
group by m.id

参见demo
结果:

> id | codes                              
> -: | :----------------------------------
>  1 | High Rise, Residential, Mobile Home