sql >> Databáze >  >> RDS >> Mysql

Jak nahradit každou další instanci konkrétního znaku v řetězci MySQL?

Měli byste zvážit uložení dat v normalizovaném schématu. Ve vašem případě by tabulka měla vypadat takto:

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

Toto schéma je flexibilnější a uvidíte proč.

Jak tedy daná data převést do nového schématu? Budete potřebovat pomocnou tabulku obsahující pořadová čísla. Protože váš sloupec je varchar(255) můžete do něj uložit pouze 128 hodnot (+ 127 oddělovačů). Ale pojďme vytvořit 1000 čísel. Můžete použít jakoukoli tabulku s dostatečným počtem řádků. Ale protože každý server MySQL má information_schema.columns stůl, použiji ho.

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;

Tato čísla použijeme jako pozici hodnot ve vašem řetězci spojením dvou tabulek.

Chcete-li extrahovat hodnotu z řetězce s oddělovači, můžete použít substring_index() funkce. Hodnota na pozici i bude

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

Ve vašem řetězci máte posloupnost klíčů následovanou jejich hodnotami. Pozice klíče je liché číslo. Pokud je tedy pozice klíče i , pozice odpovídající hodnoty bude i+1

K získání počtu oddělovačů v řetězci a omezení našeho spojení můžeme použít

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

Dotaz pro uložení dat v normalizované podobě by byl:

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

Nyní spusťte select * from normalized_table a dostanete toto:

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

Proč je tedy tento formát lepší volbou? Kromě mnoha dalších důvodů je jedním z důvodů, že jej můžete snadno převést na své staré schéma 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 |

nebo do požadovaného formátu

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 |

Pokud se nestaráte o normalizaci a chcete, aby byl tento úkol dokončen, můžete svou tabulku aktualizovat 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;

A vypusťte normalized_table .

Pak ale nebudete moci používat jednoduché dotazy jako

select *
from normalized_table
where k = 'A'

Podívejte se na ukázku na rextester.com



  1. Spouštěče SQL Server:Spouštěče DML

  2. Závažná chyba:Volání nedefinované funkce mysqli_connect() v... při propojování PHP 5.4.22 a MySQL 5.5 s Apache 2.4.7

  3. Jaké jsou výhody systému správy dat?

  4. SQLite JSON_TREE()