Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Wie ersetzt man jede andere Instanz eines bestimmten Zeichens in einer MySQL-Zeichenfolge?

Sie sollten erwägen, Ihre Daten in einem normalisierten Schema zu speichern. In Ihrem Fall sollte die Tabelle wie folgt aussehen:

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

Dieses Schema ist flexibler und Sie werden sehen warum.

Wie konvertiert man also die gegebenen Daten in das neue Schema? Sie benötigen eine Hilfstabelle mit Sequenznummern. Da Ihre Spalte varchar(255) ist Sie können darin nur 128 Werte (+ 127 Trennzeichen) speichern. Aber lassen Sie uns einfach 1000 Nummern erstellen. Sie können jede Tabelle mit genügend Zeilen verwenden. Aber da jeder MySQL-Server die information_schema.columns hat Tabelle, ich werde es verwenden.

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;

Wir werden diese Zahlen als Position der Werte in Ihrem String verwenden, indem wir die beiden Tabellen verbinden.

Um einen Wert aus einer Zeichenfolge mit Trennzeichen zu extrahieren, können Sie den substring_index() verwenden Funktion. Der Wert an Position i wird sein

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

In Ihrer Zeichenfolge haben Sie eine Folge von Schlüsseln, gefolgt von ihren Werten. Die Position einer Taste ist eine ungerade Zahl. Wenn also die Position des Schlüssels i ist , die Position des entsprechenden Werts ist i+1

Um die Anzahl der Trennzeichen in der Zeichenfolge zu erhalten und unseren Join zu begrenzen, können wir

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

Die Abfrage zum Speichern der Daten in normalisierter Form wäre:

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

Führen Sie nun select * from normalized_table aus und Sie erhalten Folgendes:

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

Warum ist dieses Format also die bessere Wahl? Neben vielen anderen Gründen ist einer, dass Sie es einfach mit

in Ihr altes Schema konvertieren können
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 |

oder in Ihr gewünschtes Format

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 |

Wenn Sie sich nicht um die Normalisierung kümmern und nur diese Aufgabe erledigen möchten, können Sie Ihre Tabelle mit

aktualisieren
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;

Und löschen Sie die normalized_table .

Aber dann können Sie keine einfachen Abfragen wie

verwenden
select *
from normalized_table
where k = 'A'

Siehe Demo auf rextester.com