Частичная замена строк в SQL - PullRequest
0 голосов
/ 04 мая 2019

Интересно, смогу ли я сделать следующее непосредственно в SQL.У меня есть текстовый столбец со значениями, разделенными -.Таким образом, значение строки примера может выглядеть 1-42-9.Я хочу сделать выбор таким, чтобы каждая строка между - заменялась другой в соответствии с некоторой логикой.В качестве примера, скажем, моя логика говорит, что каждая строка, равная 42, должна быть заменена на ABC, что даст мне 1-ABC-9.Можно ли это сделать в операторе SELECT?

Ответы [ 4 ]

2 голосов
/ 04 мая 2019

Если столбец содержит значение типа '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;

См. Демоверсию .
Для этих значений:

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 голос
/ 04 мая 2019

Можно ли это сделать в операторе SELECT?

Да, вы можете использовать функцию replace

.заменить можно использовать: -

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

Это приводит к: -

enter image description here

Если вам нужна более сложная замена, скажем, заменяя два элемента, вы можете использовать вложенные замены, отмечая, что это может быть довольно утомительным, поскольку порядок замены уместен, например, для замены -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;
0 голосов
/ 05 мая 2019

Динамическое решение, совместимое с SQLite, заключалось бы в вложении функций substr и instr для разделения списка на элементы и последующего применения логики замены к элементам.

Для таблицы strings, в которой есть столбцы idсо значениями '1-42-9', '777-5-21' и '7-55-123' (так что вы уверены, что он работает с переменными длинами элементов и охватывает 1 против 111 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_element и third_element

также, вы можете сделать это просто:

replace('-'||id||'-','-42-','-ABC-') -если вы оберните строки в дополнительную пару тире, вы сможете искать 42 независимо от его положения (начало, середина, конец)

0 голосов
/ 04 мая 2019

Используя substring и case, вы можете сделать что-то вроде следующего:

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

Вместо статического значения '1-42-9' необходимо написать имя столбца.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...