【问题标题】:Select STUFF() to simultaneously replace multiple characters in a string in SQL Server选择 STUFF() 在 SQL Server 中同时替换字符串中的多个字符
【发布时间】:2020-03-16 16:30:44
【问题描述】:

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

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

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

我正在尝试使用 STUFF() 函数来执行此操作 - 下面提供了我的查询示例 - 但理想情况下,我希望在主序。

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 倍,一次改变一个。

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

【问题讨论】:

  • 我认为这里的光标不会是世界末日。

标签: sql sql-server join left-join


【解决方案1】:

您可以使用递归 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;

【讨论】:

    【解决方案2】:
    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)
    

    【讨论】:

      【解决方案3】:

      您可以使用WHILE 代替CURSOR

      请找到演示here

      【讨论】:

        猜你喜欢
        • 2017-01-06
        • 2013-01-30
        • 2021-10-23
        • 2015-12-30
        • 1970-01-01
        • 1970-01-01
        • 2015-10-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多