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
verwendenchar_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önnenselect 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
aktualisierenupdate 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
verwendenselect *
from normalized_table
where k = 'A'
Siehe Demo auf rextester.com