Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Jak zastąpić każdą inną instancję określonego znaku w ciągu MySQL?

Należy rozważyć przechowywanie danych w znormalizowanym schemacie. W Twoim przypadku tabela powinna wyglądać tak:

| id | k |        v |
|----|---|----------|
|  1 | A |       10 |
|  1 | B |       20 |
|  1 | C |       30 |
|  2 | A | Positive |
|  2 | B | Negative |

Ten schemat jest bardziej elastyczny i zobaczysz dlaczego.

Jak więc przekonwertować podane dane do nowego schematu? Będziesz potrzebować tabeli pomocniczej zawierającej numery sekwencyjne. Ponieważ Twoja kolumna to varchar(255) możesz w nim przechowywać tylko 128 wartości (+ 127 ograniczników). Ale stwórzmy po prostu 1000 liczb. Możesz użyć dowolnej tabeli z wystarczającą liczbą wierszy. Ale ponieważ każdy serwer MySQL ma information_schema.columns stół, użyję go.

drop table if exists helper_sequence;
create table helper_sequence (i int auto_increment primary key)
    select null as i
    from information_schema.columns c1
    join information_schema.columns c2
    limit 1000;

Użyjemy tych liczb jako pozycji wartości w ciągu, łącząc dwie tabele.

Aby wyodrębnić wartość z rozdzielanego ciągu, możesz użyć substring_index() funkcjonować. Wartość na pozycji i będzie

substring_index(substring_index(t.options, '|', i  ), '|', -1)

W swoim łańcuchu masz sekwencję kluczy, po których następują jego wartości. Pozycja klucza jest liczbą nieparzystą. Więc jeśli pozycja klawisza to i , pozycja odpowiedniej wartości to i+1

Aby uzyskać liczbę ograniczników w ciągu i ograniczyć nasze łączenie, możemy użyć

char_length(t.options) - char_length(replace(t.options, '|', ''))

Zapytanie o przechowywanie danych w znormalizowanej formie to:

create table normalized_table
    select t.id
        , substring_index(substring_index(t.options, '|', i  ), '|', -1) as k
        , substring_index(substring_index(t.options, '|', i+1), '|', -1) as v
    from old_table t
    join helper_sequence s
      on s.i <= char_length(t.options) - char_length(replace(t.options, '|', ''))
    where s.i % 2 = 1

Teraz uruchom select * from normalized_table a otrzymasz to:

| id | k |        v |
|----|---|----------|
|  1 | A |       10 |
|  1 | B |       20 |
|  1 | C |       30 |
|  2 | A | Positive |
|  2 | B | Negative |

Dlaczego więc ten format jest lepszym wyborem? Oprócz wielu innych powodów, jednym z nich jest to, że możesz łatwo przekonwertować go na stary schemat za pomocą

select id, group_concat(concat(k, '|', v) order by k separator '|') as options
from normalized_table
group by id;

| id |               options |
|----|-----------------------|
|  1 |        A|10|B|20|C|30 |
|  2 | A|Positive|B|Negative |

lub w żądanym formacie

select id, group_concat(concat(k, '|', v) order by k separator ',') as options
from normalized_table
group by id;

| id |               options |
|----|-----------------------|
|  1 |        A|10,B|20,C|30 |
|  2 | A|Positive,B|Negative |

Jeśli nie zależy Ci na normalizacji i chcesz po prostu wykonać to zadanie, możesz zaktualizować swoją tabelę za pomocą

update old_table o
join (
    select id, group_concat(concat(k, '|', v) order by k separator ',') as options
    from normalized_table
    group by id
) n using (id)
set o.options = n.options;

I upuść normalized_table .

Ale wtedy nie będziesz mógł używać prostych zapytań, takich jak

select *
from normalized_table
where k = 'A'

Zobacz demo na rextester.com



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Nie można zainstalować mysql-connector-python w virtualenv

  2. MySQL WYBIERZ LIKE lub REGEXP, aby dopasować wiele słów w jednym rekordzie

  3. Wstaw używając LEFT JOIN i INNER JOIN

  4. Problem z blokadą demona MySQL

  5. Czy jest to bezpieczna/silna funkcja odkażania danych wejściowych?