Anda harus mempertimbangkan untuk menyimpan data Anda dalam skema yang dinormalisasi. Dalam kasus Anda, tabel akan terlihat seperti:
| id | k | v |
|----|---|----------|
| 1 | A | 10 |
| 1 | B | 20 |
| 1 | C | 30 |
| 2 | A | Positive |
| 2 | B | Negative |
Skema ini lebih fleksibel dan Anda akan tahu alasannya.
Jadi bagaimana cara mengubah data yang diberikan ke dalam skema baru? Anda akan membutuhkan tabel pembantu yang berisi nomor urut. Karena kolom Anda adalah varchar(255)
anda hanya dapat menyimpan 128 nilai (+ 127 pembatas) di dalamnya. Tapi mari kita buat 1000 angka saja. Anda dapat menggunakan tabel apa pun dengan baris yang cukup. Tetapi karena setiap server MySQL memiliki information_schema.columns
tabel, saya akan menggunakannya.
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;
Kami akan menggunakan angka ini sebagai posisi nilai dalam string Anda dengan menggabungkan dua tabel.
Untuk mengekstrak nilai dari string yang dibatasi, Anda dapat menggunakan substring_index()
fungsi. Nilai pada posisi i
akan menjadi
substring_index(substring_index(t.options, '|', i ), '|', -1)
Dalam string Anda, Anda memiliki urutan kunci yang diikuti oleh nilainya. Posisi kunci adalah bilangan ganjil. Jadi jika posisi kuncinya adalah i
, posisi nilai yang sesuai adalah i+1
Untuk mendapatkan jumlah pembatas dalam string dan membatasi gabungan kita, kita dapat menggunakan
char_length(t.options) - char_length(replace(t.options, '|', ''))
Kueri untuk menyimpan data dalam bentuk yang dinormalisasi adalah:
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
Sekarang jalankan select * from normalized_table
dan Anda akan mendapatkan ini:
| id | k | v |
|----|---|----------|
| 1 | A | 10 |
| 1 | B | 20 |
| 1 | C | 30 |
| 2 | A | Positive |
| 2 | B | Negative |
Jadi mengapa format ini merupakan pilihan yang lebih baik? Selain banyak alasan lain, salah satunya adalah Anda dapat dengan mudah mengonversinya ke skema lama Anda dengan
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 |
atau ke format yang Anda inginkan
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 |
Jika Anda tidak peduli dengan normalisasi dan hanya ingin tugas ini selesai, Anda dapat memperbarui tabel Anda dengan
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;
Dan lepaskan normalized_table
.
Namun, Anda tidak akan dapat menggunakan kueri sederhana seperti
select *
from normalized_table
where k = 'A'
Lihat demo di rextester.com