【问题标题】:Partially replacing strings in SQL部分替换 SQL 中的字符串
【发布时间】:2019-05-04 08:20:29
【问题描述】:

我想知道我是否可以直接在 SQL 中执行以下操作。我有一个文本格式的列,其值由- 分隔。因此,示例行值可能看起来像 1-42-9。我想进行选择,以便根据某些逻辑将- 之间的每个字符串替换为另一个字符串。例如,假设我的逻辑是每个等于42 的字符串都应该替换为ABC,这将给我1-ABC-9。这可以在SELECT 语句中完成吗?

【问题讨论】:

  • 可以考虑使用sql replace()函数。看看this
  • 感谢您的快速回复。假设一个值看起来像1-11-111。如果我使用replace,我如何区分1、11和111?
  • 可以将-11-替换为-ABC-,例如
  • 你使用 SQLite 吗?它的功能非常有限
  • @AlexYes,是的,我确实使用 SQLite 有几个原因,但我知道这些限制。感谢您指出这一点! :)

标签: sql sqlite


【解决方案1】:

如果该列包含类似'1-42-9' 的值,并且您想搜索'42' 以替换为'ABC',那么您必须考虑所有情况,例如:

  • '42' 在列的开头
  • '42' 在列的中间
  • '42' 在列的末尾
  • '42' 是该列的唯一值

这4种情况可以用更复杂但更精确的方法来处理:

select substr(
  replace('-' || col || '-', '-42-', '-ABC-'), 
  2,
  length(replace('-' || col || '-', '-42-', '-ABC-')) - 2
) NewCol
from tablename;

请参阅demo
对于这些值:

create table tablename (col TEXT);
insert into tablename (col) values
('1-42-9'),
('42-1-9'),
('9-1-42'),
('42'),
('1-100-9');

结果是:

| NewCol  |
| ------- |
| 1-ABC-9 |
| ABC-1-9 |
| 9-1-ABC |
| ABC     |
| 1-100-9 |

【讨论】:

  • 这很有趣。您将如何调整代码以适应每行有四个数字的情况?例如。 1-32-5-61?您将如何一次性添加多个条件?因此,例如 1 被 A 替换,32 被 B 替换等。值得一提的是,没有每行中只有一个值的情况。所有行的格式为number-number-number-number,数字为1 位或2 位数字。谢谢。
  • 该代码适用于任意数量的数字,如果您想要 1 个替换,它们是 1 位还是 2 位或更多位都没有关系。同时更换 2 个或多个替换件会变得复杂。
【解决方案2】:

使用substringcase,您可以执行以下操作:

select case when '1-42-9' like '%-42-%'
then replace('1-42-9','-42-', '-ABC-' )
else '1-42-9' end 

你需要写列名,而不是'1-42-9'的静态值。

【讨论】:

    【解决方案3】:

    这可以在 SELECT 语句中完成吗?

    是的,您可以使用replace function

    只需执行 1 个替换即可:-

    SELECT replace(mycolumn,'-42-','ABC') AS mycolumn FROM mytable;
    

    演示这种简单单数替换的工作示例是:-

    DROP TABLE IF EXISTS mytable;
    CREATE TABLE IF NOT EXISTS mytable (mycolumn);
    INSERT INTO mytable VALUES ('1-42-9'),('1429'); -- add some data (one row to be changed, the other not to be changed)
    SELECT replace(mycolumn,'-42-','ABC') AS mycolumn FROM mytable; -- Do the replace maintaing the column name
    

    这导致:-

    如果您想要更复杂的替换,比如替换两个项目,您可以使用嵌套替换,请注意这可能非常繁琐,因为替换顺序是相关的,例如将 -9 替换为 XYZ 并将 -42- 替换为 ABC 以便 1 -42-9 变成 1ABCXYZ 然后你可以使用 :-

    SELECT replace(replace(mycolumn,'-9','-XYZ'),'-42-','ABC') AS mycolumn FROM mytable;
    

    如果您想要多个替换,其中只有 1 个可以完成,例如 -42- 替换为 ABC 或 -43- 替换为 DEF 或 -44- 替换为 GHI,那么您可以使用 CASE WHEN THEN END 构造,如下所示: -

    SELECT
        CASE 
          WHEN instr(mycolumn,'-42-') THEN replace(mycolumn,'-42-','ABC')
          WHEN instr(mycolumn,'-43-') THEN replace(mycolumn,'-43-','DEF')
          WHEN instr(mycolumn,'-44-') THEN replace(mycolumn,'-44-','GHI')
          ELSE mycolumn
      END AS mycolumn
    FROM mytable;
    

    【讨论】:

      【解决方案4】:

      与 SQLite 兼容的动态解决方案是嵌套 substr 和 instr 函数以将列表拆分为元素,然后将替换逻辑应用于元素。

      对于一个表strings,其列id 的值为'1-42-9''777-5-21''7-55-123'(因此您确定它适用于可变长度的元素并涵盖1 与@987654328 @case),它会是:

      SELECT
       input 
      ,first_element || '-' ||
       CASE second_element 
          WHEN '42' THEN 'ABC'
          WHEN '5' THEN 'DEF'
          ELSE second_element
       END || '-' ||
       third_element as output
      FROM (
          select 
          id as input,
          substr(
            id,
            1,
            instr(id,'-')-1
          ) as first_element,             
          substr(
            substr(id,instr(id,'-')+1,100),
            1,
            instr(substr(id,instr(id,'-')+1,100),'-')-1
          ) as second_element
          ,substr(
            substr(id,instr(id,'-')+1,100),
            instr(substr(id,instr(id,'-')+1,100),'-')+1,
            100
          ) as third_element
          from strings
      ) t       
      

      fiddle

      (可能更漂亮,但它正在工作:))

      这仅适用于具有 3 个由破折号分隔的元素的字符串列表

      如果您想替换任何位置的某个元素,只需将相同的 CASE 语句应用于 first_elementthird_element

      另外,您可以这样做:

      replace('-'||id||'-','-42-','-ABC-') - 如果您将字符串包装成另外一对破折号,您将能够搜索42,无论其位置如何(开始、中间、结束)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-03-04
        • 1970-01-01
        • 2012-07-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多