【问题标题】:replacing part of a string with value from another column postgresql用另一列 postgresql 中的值替换字符串的一部分
【发布时间】:2020-11-03 14:07:00
【问题描述】:

我有一个表格,其中一列中的突变信息是三个字母代码中的氨基酸变化如下:

氨基酸变化 ---------------------- NP_006209.2:p.Thr1025Ala NP_203524.1:p.Gly12Asp NP_000537.3:p.Arg273Cys NP_004324.2:p.Val600Glu NP_000537.3:p.Ser215Ile

在另一个表中,我有如下氨基酸的三个字母代码和一个字母代码:

three_letters|one_letters
-------------|-----------
Ala          |A          
Arg          |R          
Asn          |N          
Asp          |D             
...
Val          |V          
Asx          |B          
Glx          |Z          
Ter          |*          

我需要在我的突变表中添加一个新列,其中一个字母代码中的氨基酸如下:

新专栏 ------------ p.T1025AG12D p.R273C p.V600ES215页

【问题讨论】:

    标签: sql postgresql replace


    【解决方案1】:

    只要更改代码始终是三个字母后跟一个或多个数字后跟三个字母,您就可以使用正则表达式解决这个问题。

    regexp_match(change, 'p.(\D{3})(\d+)(\D{3})')
    

    这会返回一个数组,该数组可用于连接到您的查找表,然后重构缩短的代码。

    with split as (
      select *, 
             regexp_match(change, 'p.(\D{3})(\d+)(\D{3})') as parts
        from changes
    )
    select s.*, 
           concat('p.', 
                  coalesce(x1.one_letters, '?'), 
                  parts[2], 
                  coalesce(x2.one_letters, '?') 
           ) as encoded_change
      from split s
      left join xlate x1 on x1.three_letters = s.parts[1]
      left join xlate x2 on x2.three_letters = s.parts[3];
    

    【讨论】:

      【解决方案2】:

      您的字符串是一种非常特殊的格式。前缀看起来像一个固定长度。然后是三个字符,一个数字(大概是一个位置),然后是另外三个字符。

      如果总是这样,您就不需要任何真正复杂的机器来进行更换。您可以只使用字符串操作:

      with replacements as (
            select 'Thr' as three_letters, 'T' as one_letter union all
            select 'Ala' as three_letters, 'A' as one_letter
           ) 
      select v.*, 
             left(mutation, 14) || r1.one_letter || replace(substr(mutation, 18), r2.three_letters, r2.one_letter)
      from (values ('NP_006209.2:p.Thr1025Ala')) v(mutation) left join
           replacements r1
           on r1.three_letters = substr(mutation, 15, 3) left join
           replacements r2
           on r2.three_letters = right(mutation, 3);
      

      我实际上建议您更改数据结构,以便值不会全部编码在单个字符串中。将结果放在多列中:

      • name
      • from_amino_acid
      • to_amino_acid
      • position

      其实我不知道:之前发生了什么,也不知道p.是否重要。您可能还希望将其拆分为不止一列。您可以使用这样的逻辑来拆分字符串:

      select split_part(mutation, ':', 1) as name,
             substring(split_part(mutation, ':', 2), 3, 3) as from_amino_acid,
             (regexp_matches(split_part(mutation, ':', 2), '[0-9]+'))[1] as position,
             right(mutation, 3) as to_amino_acid
      from (values ('NP_006209.2:p.Thr1025Ala')) v(mutation);
      

      这将简化您的 SQL,可能还会简化您的分析。

      【讨论】:

        【解决方案3】:

        @Mike Organek 提出的解决方案的替代方案是创建一个简短的函数来为您执行此转换。

        数据样本:

        CREATE TEMPORARY TABLE map (three_letters text, one_letters text);
        INSERT INTO map 
        VALUES ('Val','V'),('Glu','E'),('Thr','T'),('Ala','A');
        

        功能:

        CREATE OR REPLACE FUNCTION change_amino_acid(text)
        RETURNS TEXT AS $BODY$
        DECLARE i RECORD; acid TEXT;
        BEGIN
        acid := trim((string_to_array($1, ':p.'))[2]);
        FOR i IN SELECT * FROM map 
          WHERE three_letters = ANY(regexp_split_to_array(acid, '\d+'))
        LOOP
          acid := replace(acid,i.three_letters,i.one_letters);
        END LOOP;
        RETURN 'p.'||acid;
        END; $BODY$ LANGUAGE plpgsql;
        

        如何调用函数:

        SELECT 
          change_amino_acid('NP_006209.2:p.Thr1025Ala'),
          change_amino_acid('NP_004324.2:p.Val600Glu');
        
         change_amino_acid | change_amino_acid 
        -------------------+-------------------
         p.T1025A          | p.V600E
        

        之后你需要做的就是使用函数UPDATE你的桌子

        UPDATE my_table 
        SET newcolum = change_amino_acid(long_amino_acid);
        

        【讨论】:

          猜你喜欢
          • 2019-08-08
          • 2022-11-25
          • 2020-11-09
          • 2023-03-20
          • 1970-01-01
          • 2011-03-25
          相关资源
          最近更新 更多