SQL连接表和CONCAT的CASE

SQL连接表和CONCAT的CASE,sql,sql-server,sql-server-2016,Sql,Sql Server,Sql Server 2016,我是SQL新手。。。我需要连接两个表,如下所示 Table A | id | Recipe_Web_Codes | |----|--------------------| | 1 | GF VGT | | 2 | | | 3 | VGN | 并生成下表: RESULT | id | Recipe_Web_Codes | Wecode_Fullname | Color

我是SQL新手。。。我需要连接两个表,如下所示

Table A
| id | Recipe_Web_Codes   |
|----|--------------------|
|  1 | GF VGT             |
|  2 |                    |
|  3 | VGN                |
并生成下表:

RESULT
| id | Recipe_Web_Codes | Wecode_Fullname               | Color            |
|-------------------------------------------------------|------------------|
| 1  | GF VGT           | Gluten Friendly, Vegetarian   | #6ca4b6, #ff6038 |
| 2  |                  |                               |                  |
| 3  | VGN              | Vegan Friendly                | #97002d          |
我真的不知道从哪里开始。我尝试了这个方法,但在如何将案例结果连接到单个字段上遇到了困难。我走对了吗

select Recipe_Web_Codes, Webcode_Fullname =  
    case 
        when Recipe_Web_Codes like '%VGT%' then (select Webcode_Fullname FROM TABLE_B where Recipe_Web_Code = 'VGT')
        when Recipe_Web_Codes like '%VGN%' then (select Webcode_Fullname FROM TABLE_B where Recipe_Web_Code = 'VGN')
        when Recipe_Web_Codes like '%GF%' then (select Webcode_Fullname FROM TABLE_B where Recipe_Web_Code = 'GF')
    end, 
    Color = 
    case 
        when Recipe_Web_Codes like '%VGT%' then (select Color FROM TABLE_B where Recipe_Web_Code = 'VGT')
        when Recipe_Web_Codes like '%VGN%' then (select Color FROM TABLE_B where Recipe_Web_Code = 'VGN')
        when Recipe_Web_Codes like '%GF%' then (select Color FROM TABLE_B where Recipe_Web_Code = 'GF')
    end
from TABLE_A

编辑:它只是点击我,我错过了一个非常重要的点,为什么我需要聚合这些字符串。生成的表将由另一个单独的进程导出为JSON,因此没有必要提及数据库规范化。此外,这是SQL 2016 SP2,因此我没有可用的字符串_agg功能

您可以使用表的左联接来完成此操作,聚合函数在SQL Server 2017+中工作:

select a.id, a.Recipe_Web_Codes,
  string_agg(b.Webcode_Fullname, ', ') Webcode_Fullname,
  string_agg(b.Color, ', ') Color
from Table_A a left join Table_B b
on ' ' + a.Recipe_Web_Codes + ' ' like '% ' + b.Recipe_Web_Code + ' %'
group by a.id, a.Recipe_Web_Codes
order by a.id
看。 结果:


您不应该在一列中存储多个值,因此我建议您修复数据模型

也就是说,您可以通过分离字符串并重新聚合来做您想做的事情:

select a.*, b.*
from a outer apply
     (select string_agg(b.Webcode_Fullname, ',') as Webcode_Fullname,
             string_agg(b.Webcode_Fullname, ',') as Colors
      from string_split(a.recipe_web_codes, ' ') s join
           b
           on s.value = b.Recipe_Web_Code
     ) b;
非常重要:string_split不能保证值的顺序。如果结果字符串的顺序很重要,则可以使用以下逻辑处理此问题(假设没有重复项):

select a.*, b.*
from a outer apply
     (select string_agg(b.Webcode_Fullname, ',') within group (order by charindex(b.Recipe_Web_Codeas, a.recipe_web_codes)) as Webcode_Fullname,
             string_agg(b.Webcode_Fullname, ',') within group (order by charindex(b.Recipe_Web_Codeas, a.recipe_web_codes)) as Colors
      from string_split(a.recipe_web_codes, ' ') s join
           b
           on s.value = b.Recipe_Web_Code
     ) b;
让我再次强调,您应该将精力放在修复数据模型上,为配方web代码创建一个单独的表,每个代码一行

编辑:

旧版本的一个解决方案是递归CTE:

with bs as (
      select b.*, row_number() over (order by id) as seqnum
      from b
     ),
     cte as (
      select a.id, convert(varchar(max), Recipe_Web_Codes) as fullnames, convert(varchar(max), Recipe_Web_Codes)  as colors, 1 as ind
      from a
      union all
      select cte.id,
             replace(cte.fullnames, bs.Recipe_Web_Code, bs.Webcode_Fullname),
             replace(cte.colors, bs.Recipe_Web_Code, bs.color),
             1 + cte.ind
      from cte join
           bs
           on cte.ind = bs.seqnum and ind < 10
     )
select cte.id, cte.fullnames, cte.colors
from (select cte.*, max(ind) over (partition by id) as max_ind
      from cte
     ) cte
where ind = max_ind ;

这是一个非常糟糕的设计。请学习数据库规范化。由于表A中存在配方代码,您的数据库设计非常奇怪。表A应该引用表B的id。在任何人回答之前,您是否可以更改它?实际上,就您当前显示的字段而言,我不明白您为什么有两个表。关于表/db设计的约定很糟糕,不是我的工作,但这是我必须处理的问题。Darn,我有SQL Server 2016 SP2,我有SQL Server 2016 SP2,所以字符串\u agg对我不可用。同意数据库设计。。。如果你看到整个应用程序的架构,你会感到震惊。看起来很有希望。。。。我不太明白发生了什么,所以我被困在这里:Msg 240,16级,状态1,行1类型在递归查询cte的全名列中的锚和递归部分之间不匹配。Msg 240,级别16,状态1,行1类型在递归查询cte列颜色中的锚和递归部分之间不匹配。确定,通过添加cast replacecte.fullnames、bs.Recipe_Web_代码、bs.Webcode_Fullname作为varcharmax、cast replacecte.colors、bs.Recipe_Web_代码、bs.color作为varcharmax修复了类型匹配,但它似乎只替换了屏幕上的最后一项list@Geto . . . 你看到DB小提琴了吗?所有代码都已替换。递归CTE是有效的。我认为它与数据库上的类型有关,请看这个更新的提琴:顺便说一句,这对我来说都是新的,我对CTE一无所知,我仍然在尝试围绕递归CTE。我仍然不明白为什么它只替换最后一个字段
select a.*, b.*
from a outer apply
     (select string_agg(b.Webcode_Fullname, ',') within group (order by charindex(b.Recipe_Web_Codeas, a.recipe_web_codes)) as Webcode_Fullname,
             string_agg(b.Webcode_Fullname, ',') within group (order by charindex(b.Recipe_Web_Codeas, a.recipe_web_codes)) as Colors
      from string_split(a.recipe_web_codes, ' ') s join
           b
           on s.value = b.Recipe_Web_Code
     ) b;
with bs as (
      select b.*, row_number() over (order by id) as seqnum
      from b
     ),
     cte as (
      select a.id, convert(varchar(max), Recipe_Web_Codes) as fullnames, convert(varchar(max), Recipe_Web_Codes)  as colors, 1 as ind
      from a
      union all
      select cte.id,
             replace(cte.fullnames, bs.Recipe_Web_Code, bs.Webcode_Fullname),
             replace(cte.colors, bs.Recipe_Web_Code, bs.color),
             1 + cte.ind
      from cte join
           bs
           on cte.ind = bs.seqnum and ind < 10
     )
select cte.id, cte.fullnames, cte.colors
from (select cte.*, max(ind) over (partition by id) as max_ind
      from cte
     ) cte
where ind = max_ind ;