按连接字段加入(CSV格式)

时间:2018-04-04 19:28:19

标签: sql sql-server csv lookup sql-server-2017

更新:我完全清楚这是一个糟糕的RDBMS实践,但问题不在于它是否以及如何重新培训创建此体系结构的DBA。问题是如何解决我手头的情况。我很感谢社区的帮助,并且必须承认这确实是一个有趣的问题。

在SQL Server 2017中,我有一个包含代码的查找表和一个包含CSV格式代码的事务表:

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

并且,交易表具有:

cd
c1
c1,c2
c1,c2,c3

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

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

输出需要到事务表中的另一列:

id
10
10,20
10,20,30

1 个答案:

答案 0 :(得分:1)

您可以先将逗号删除到列表中,然后加入并获取代码的正确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 SERVER 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