Overweeg om uw gegevens op te slaan in een genormaliseerd schema. In jouw geval zou de tabel er als volgt uit moeten zien:
| id | k | v |
|----|---|----------|
| 1 | A | 10 |
| 1 | B | 20 |
| 1 | C | 30 |
| 2 | A | Positive |
| 2 | B | Negative |
Dit schema is flexibeler en u zult zien waarom.
Dus hoe de gegeven gegevens in het nieuwe schema om te zetten? U hebt een hulptabel nodig met volgnummers. Aangezien uw kolom varchar(255)
. is je kunt er maar 128 waarden (+ 127 scheidingstekens) in opslaan. Maar laten we gewoon 1000 getallen maken. U kunt elke tabel met voldoende rijen gebruiken. Maar aangezien elke MySQL-server de information_schema.columns
. heeft tafel, ik zal hem gebruiken.
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;
We zullen deze getallen gebruiken als positie van de waarden in je string door de twee tabellen samen te voegen.
Om een waarde uit een string met scheidingstekens te extraheren, kunt u de substring_index()
. gebruiken functie. De waarde op positie i
zal zijn
substring_index(substring_index(t.options, '|', i ), '|', -1)
In je string heb je een reeks sleutels gevolgd door zijn waarden. De positie van een sleutel is een oneven getal. Dus als de positie van de sleutel i
. is , is de positie van de corresponderende waarde i+1
Om het aantal scheidingstekens in de string te krijgen en onze join te beperken, kunnen we
. gebruikenchar_length(t.options) - char_length(replace(t.options, '|', ''))
De vraag om de gegevens in een genormaliseerde vorm op te slaan zou zijn:
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
Voer nu select * from normalized_table
uit en je krijgt dit:
| id | k | v |
|----|---|----------|
| 1 | A | 10 |
| 1 | B | 20 |
| 1 | C | 30 |
| 2 | A | Positive |
| 2 | B | Negative |
Dus waarom is dit formaat een betere keuze? Naast vele andere redenen, is een ervan dat je het gemakkelijk naar je oude schema kunt converteren met
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 |
of naar uw gewenste formaat
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 |
Als normalisatie u niet interesseert en u wilt gewoon dat deze taak wordt uitgevoerd, kunt u uw tabel bijwerken met
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;
En laat de normalized_table
vallen .
Maar dan kunt u geen eenvoudige zoekopdrachten gebruiken, zoals
select *
from normalized_table
where k = 'A'
Bekijk de demo op rextester.com