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

MySQL converte il tipo di dati CHAR(32) in BINARY(16) senza perdere dati

Sembra che tu voglia avere un UUID rappresentato come una stringa di cifre esadecimali. Questi normalmente hanno quattro trattini, quindi la lunghezza è in realtà di 36 caratteri. Ma se rimuovi i trattini, possono essere 32 caratteri.

mysql> SELECT UUID();
+--------------------------------------+
| UUID()                               |
+--------------------------------------+
| b4d841ec-5220-11e9-901f-a921a9eb9f5b |
+--------------------------------------+

mysql> SELECT REPLACE(UUID(), '-', '');
+----------------------------------+
| REPLACE(UUID(), '-', '')         |
+----------------------------------+
| d3dbd450522011e9901fa921a9eb9f5b |
+----------------------------------+

Ma in una stringa esadecimale, ogni due caratteri rappresenta dati che potrebbero essere codificati in un byte di dati binari. Ad esempio, FF è il valore esadecimale per 255, che è il valore massimo di un byte. Pertanto le stringhe esadecimali richiedono il doppio dei byte dei dati equivalenti in binario. Se lo spazio è limitato, potresti voler convertire i tuoi valori UUID in binari in modo da poterli archiviare in metà spazio.

Puoi farlo con la funzione UNHEX() .

mysql> SELECT UNHEX(REPLACE(UUID(), '-', ''));
+---------------------------------+
| UNHEX(REPLACE(UUID(), '-', '')) |
+---------------------------------+
| $S,vR!??!??[                      |
+---------------------------------+

I dati binari non sono piacevoli da visualizzare o digitare nelle interfacce orientate all'uomo, perché alcuni byte corrispondono a caratteri non stampabili.

Ma quando hai fatto ALTER TABLE table_name MODIFY device_uuid BINARY(16) , non hai decodificato le stringhe esadecimali con UNHEX() . Nella migliore delle ipotesi, ciò ha causato il mapping dei primi 16 byte di caratteri esadecimali ASCII ai 16 byte della colonna BINARY(16) e a quel punto ha troncato la stringa. È come se lo facessi su ogni riga:

mysql> SELECT LEFT(REPLACE(UUID(), '-', ''), 16);
+------------------------------------+
| LEFT(REPLACE(UUID(), '-', ''), 16) |
+------------------------------------+
| 364e6db8522211e9                   |
+------------------------------------+

I primi 16 byte sono ancora cifre esadecimali. I byte sono valori ASCII per quelle cifre, non l'equivalente binario di ciascuna coppia di cifre. Gli ultimi 16 byte di ogni stringa sono stati troncati e non archiviati. Se quei dati erano importanti, spero che tu abbia un backup del tuo database, perché il ripristino di quel backup è ora l'unico modo per recuperare quei dati.

Quello che avresti dovuto fare è il seguente:

ALTER TABLE table_name ADD COLUMN device_uuid_bin BINARY(16);
UPDATE table_name SET device_uuid_bin = UNHEX(device_uuid);

...check the data to make sure the conversion worked... 
...test any applications work with the binary data... 

ALTER TABLE table_name DROP COLUMN device_uuid;