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