sql >> Database teknologi >  >> RDS >> Mysql

Hvordan erstatter man hver anden forekomst af en bestemt karakter i en MySQL-streng?

Du bør overveje at gemme dine data i et normaliseret skema. I dit tilfælde skulle tabellen se sådan ud:

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

Dette skema er mere fleksibelt, og du vil se hvorfor.

Så hvordan konverteres de givne data til det nye skema? Du skal bruge en hjælpetabel med sekvensnumre. Da din kolonne er varchar(255) du kan kun gemme 128 værdier (+ 127 skilletegn) i den. Men lad os bare skabe 1000 numre. Du kan bruge enhver tabel med nok rækker. Men da enhver MySQL-server har information_schema.columns tabel, vil jeg bruge det.

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;
 

Vi vil bruge disse tal som placering af værdierne i din streng ved at forbinde de to tabeller.

For at udtrække en værdi fra en afgrænset streng kan du bruge substring_index() fungere. Værdien ved position i vil være

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

I din streng har du en sekvens af taster efterfulgt af dens værdier. En nøgles position er et ulige tal. Så hvis nøglens position er i , vil positionen for den tilsvarende værdi være i+1

For at få antallet af skilletegn i strengen og begrænse vores join, kan vi bruge

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

Forespørgslen om at gemme dataene i en normaliseret form ville væ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
 

Kør nu select * from normalized_table og du får dette:

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

Så hvorfor er dette format et bedre valg? Udover mange andre grunde er den ene, at du nemt kan konvertere det til dit gamle skema med

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 |
 

eller til dit ønskede 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 |
 

Hvis du er ligeglad med normalisering og bare vil have denne opgave udført, kan du opdatere din tabel med

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;
 

Og slip normalized_table .

Men så vil du ikke være i stand til at bruge simple forespørgsler som

select *
from normalized_table
where k = 'A'
 

Se demo på rextester.com



  1. Skift Excel-datonummer til Oracle-dato

  2. Oversigt over DBCC CheckDB-funktion

  3. Sådan genereres DDL for alle tabeller i en database i MySQL

  4. RMAN fejler med RMAN-06900 RMAN-06901 ORA-04031