需要从另一个表中获取ID的描述,这些表用管道分隔

时间:2018-09-28 11:35:38

标签: sql sql-server

我有两个表table1和table2 在table1中,有一列名为typeids的ID,其中ID用竖线分隔

ex: 2|3|4 --> these ids are the primary key in table2

table2包含ID,其描述类似于

2-text1
3-text2
4-text3

现在我需要获取table1的内容,但是2 | 3 | 4将替换为

text1|text2|text3

1 个答案:

答案 0 :(得分:2)

这是一个非常糟糕的数据库设计,正如其他人所说的那样,您应该尽最大的努力来更改它。


也就是说,这是可能的。这就像罪恶的丑陋,我相信它的表现就像狗一样,但是您可以将其归咎于数据库设计人员。简而言之,您需要在id字符上拆分|字符串,将join的每个元素拆分为table2,然后使用for xml将它们重新连接在一起。当您使用SQL Server 2016时,可以使用STRING_SPLIT代替我在下面使用的功能,尽管由于我目前无法访问这里的2016框,所以我们是(Working example):

create function dbo.StringSplit
(
    @str nvarchar(4000) = ' '               -- String to split.
    ,@delimiter as nvarchar(1) = ','        -- Delimiting value to split on.
    ,@num as int = null                     -- Which value to return.
)
returns table
as
return
(
                        -- Start tally table with 10 rows.
    with n(n)   as (select n from (values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n(n))
                        -- Select the same number of rows as characters in isnull(@str,'') as incremental row numbers.
                    -- Cross joins increase exponentially to a max possible 10,000 rows to cover largest isnull(@str,'') length.
        ,t(t)   as (select top (select len(isnull(@str,'')) a) row_number() over (order by (select null)) from n n1,n n2,n n3,n n4)
                            -- Return the position of every value that follows the specified delimiter.
        ,s(s)   as (select 1 union all select t+1 from t where substring(isnull(@str,''),t,1) = @delimiter)
                            -- Return the start and length of every value, to use in the SUBSTRING function.
                    -- ISNULL/NULLIF combo handles the last value where there is no delimiter at the end of the string.
        ,l(s,l) as (select s,isnull(nullif(charindex(@delimiter,isnull(@str,''),s),0)-s,4000) from s)
    select rn as ItemNumber
            ,Item
    from(select row_number() over(order by s) as rn
                ,substring(isnull(@str,''),s,l) as item
        from l
        ) a
    where rn = @num       -- Return a specific value where specified,
        or @num is null   -- Or everything where not.
)
go

declare @t1 table (id varchar(10));
insert into @t1 values
 ('2|3|4')
,('5|6|7');

declare @t2 table (id varchar(1), description varchar(10));
insert into @t2 values
 ('2','text1')
,('3','text2')
,('4','text3')
,('5','text4')
,('6','text5')
,('7','text6')
;
select t1.id
      ,stuff((select '|' + t2.description
              from @t1 as t1a
                  cross apply dbo.StringSplit(t1a.id,'|',null) as s
                  join @t2 as t2
                      on s.Item = t2.id
              where t1.id = t1a.id
              for xml path('')
             ),1,1,''
            ) as t
from @t1 as t1;

输出:

+-------+-------------------+
|  id   |         t         |
+-------+-------------------+
| 2|3|4 | text1|text2|text3 |
| 5|6|7 | text4|text5|text6 |
+-------+-------------------+