选择STUFF()以同时替换SQL Server中的字符串中的多个字符

时间:2020-03-16 16:30:44

标签: sql sql-server join left-join

我有大量的非冗余ID和序列,如下所示(表A)。

enter image description here

在第二张表中,我具有要更改的ID,位置和字母的多条记录(表B)。

enter image description here

我想做的就是根据表B中给出的更改替换表A主序列中特定位置的特定字母。

我正在尝试使用STUFF()函数-下面提供了我的查询示例-但理想情况下,我希望对ProteinID P12111进行全部4次更改在主序列中同时进行。

SELECT 
    A.[proteinID],
    STUFF(A.[proteinSeq], CAST(B.[position] AS INT), 1, B.[change_to] ) AS [proteinSeq]
FROM 
    [dbo].[TableA] A
LEFT OUTER JOIN 
    [dbo].[TableB] B ON A.proteinID = B.proteinID

通过上述查询,我​​得到了第二个序列的4倍,一次有一个改变。

enter image description here

我不确定是否可以使用STUFF()实现请求的输出。另一方面,如果可能的话,我想避免使用CURSOR。有什么建议吗?

3 个答案:

答案 0 :(得分:0)

您可以使用递归CTE。我有点不确定change_from指的是-您更改该位置的值还是不更改。无论如何,逻辑似乎是:

with bb as (
      select b.*,
             row_number() over (partition by proteinid order by seq) as seqnum
      from b
     ),
     cte as 
      select a.proteinid, a.seq, 1 as lev
      from a
      union all
      select cte.proteinid, stuff(a.seq, b.position, 1, b.change_to), lev + 1
      from cte join
           b
           on cte.lev = b.seqnum and
              cte.proteinid = a.proteinid
    )
select cte.*
from (select cte.*,
             row_number() over (partition by proteinid order by lev desc) as seqnum
      from cte
     ) cte
where seqnum = 1;

答案 1 :(得分:0)

WITH aa AS (
      -- get positions and how many times we need to make changes
      SELECT a.*,
             row_number() over (partition by a.proteinid order by a.seq) as seqnum
             , b.position
      from [dbo].[TableA] a
      RIGHT OUTER JOIN 
      [dbo].[Tableb] b on
      b.proteinid=a.proteinid

     ),
     cte AS
      (
      -- Get an anchor
      SELECT a.proteinid, a.seq, 1 AS lev
      FROM [dbo].[Tablea] a
      UNION ALL   
      -- CAST is needed to match the data types, choose yours as needed
      SELECT cte.proteinid, CAST(stuff(cte.seq, b.position, 1, b.changeto) AS VARCHAR(100)), lev + 1
      FROM cte 
      INNER JOIN aa
      ON cte.lev = aa.seqnum
      AND cte.proteinid = aa.proteinid
      INNER JOIN [dbo].[TableB] b
      ON cte.proteinid = b.proteinid
      AND aa.position=b.position
    )

SELECT * FROM cte
-- We filter as only need final change
WHERE cte.lev=
(SELECT MAX(t1.lev) FROM cte AS t1 
WHERE t1.proteinid=cte.proteinid)

答案 2 :(得分:0)

您可以使用WHILE代替CURSOR

请找到演示here

相关问题