通过连接字段加入(CSV 格式)

Join by concatenated field (in CSV format)

更新: 我完全知道这是一个糟糕的 RDBMS 实践,但问题不是问它是否是以及我如何重新培训创建这个的 DBA建筑学。问题是我如何解决手头的情况。我感谢社区的帮助,并且必须承认这确实是一个有趣的问题。

在 SQL Server 2017 中,我有一个包含代码的查找 table 和一个带有 CSV 格式代码的交易 table:

CREATE TABLE #t(cd VARCHAR(100))
CREATE TABLE #cd (id INT, cd VARCHAR (1000))

INSERT INTO #t SELECT 'c1'
INSERT INTO #t SELECT 'c1,c2'
INSERT INTO #t SELECT 'c1,c2,c3'

INSERT INTO #cd SELECT 10, 'c1'
INSERT INTO #cd SELECT 20, 'c2'
INSERT INTO #cd SELECT 30, 'c3'

所以,查找是

id  cd
10  c1
10  c1
20  c2
30  c3

并且,交易 table 有:

cd
c1
c1,c2
c1,c2,c3

我需要将代码替换为其各自的 ID,同时将这些代码保留为 CSV 格式。

我想避开游标,因为它太慢了。有没有一种方法可以有效地解析代码、执行 JOIN 和重新组合 ID?我想 COALESCE 可能有用,但需要帮助来应用它。也许,在 t-SQL 中已经有一个函数可以执行这种类型的查找。

输出需要到交易中的另一列table:

id
10
10,20
10,20,30

您可以先将逗号删除到列表中,然后加入并获取代码的正确 ID,然后用逗号将它们添加回去。我预先使用 row_number 来获得一个独特的东西,以便在我的查询中重新加入。

See live demo

CREATE TABLE #t(cd VARCHAR(100))
CREATE TABLE #cd (id INT, cd VARCHAR (1000))

INSERT INTO #t SELECT 'c1'
INSERT INTO #t SELECT 'c1,c2'
INSERT INTO #t SELECT 'c1,c2,c3'

INSERT INTO #cd SELECT 10, 'c1'
INSERT INTO #cd SELECT 20, 'c2'
INSERT INTO #cd SELECT 30, 'c3'


; WITH X AS 
(
    SELECT 
     C.id,P1.rn
    FROM
     (
     SELECT *, row_number() over( order by (select 1)) rn,
     cast('<X>'+replace(P.cd,',','</X><X>')+'</X>' as XML) AS xmlitems FROM #t P
     )P1
     CROSS APPLY
     ( 
     SELECT fdata.D.value('.','varchar(100)') AS splitdata 
     FROM P1.xmlitems.nodes('X') AS fdata(D)) O
     LEFT JOIN #cd C
     ON C.cd=  LTRIM(RTRIM(O.splitdata ))
    ) 

SELECT 
    rn,
    id= STUFF((
  SELECT ',' + cast(id as varchar(100)) FROM X AS x2 
  WHERE x2.rn = x.rn
  ORDER BY rn FOR XML PATH, 
  TYPE).value(N'.[1]',N'varchar(max)'), 1, 1, '')
  FROM 
  X
GROUP BY rn 

注意: 使用 SQL server 2017 您还可以使用 SPLIT_STRING() 函数 和 STRING_AGG() 函数

SQL 服务器 2017 代码:

select 
 id=STRING_AGG(id,',')
 from
(
  select V=value, rn
  from
      (
        select 
             rn=row_number() over( order by (select 1)), 
             cd 
        from #T
      )T
   cross apply STRING_SPLIT(cd, ',') 
 )  T
left join #cd C
     on cd= v
group by rn