Bagaimana cara memperbaiki kesalahan "Nilai string salah"?

162

Setelah memperhatikan aplikasi yang cenderung membuang email acak karena kesalahan nilai string, saya pergi dan beralih banyak kolom teks untuk menggunakan utf8charset kolom dan susunan kolom default ( utf8_general_ci) sehingga akan menerimanya. Ini memperbaiki sebagian besar kesalahan, dan membuat aplikasi berhenti mendapatkan kesalahan sql ketika itu memukul email non-latin juga.

Meskipun demikian, beberapa email masih menyebabkan program mengalami kesalahan nilai string yang salah: (Incorrect string value: '\xE4\xC5\xCC\xC9\xD3\xD8...' for column 'contents' at row 1)

Kolom isi adalah MEDIUMTEXTdatatybe yang menggunakan utf8charset kolom dan susun utf8_general_cikolom. Tidak ada bendera yang dapat saya toggle di kolom ini.

Ingatlah bahwa saya tidak ingin menyentuh atau bahkan melihat kode sumber aplikasi kecuali benar-benar diperlukan:

  • Apa yang menyebabkan kesalahan itu? (ya, saya tahu emailnya penuh dengan sampah acak, tapi saya pikir utf8 akan sangat permisif)
  • Bagaimana saya bisa memperbaikinya?
  • Apa kemungkinan dampak dari perbaikan seperti itu?

Satu hal yang saya pertimbangkan adalah beralih ke utf8 varchar ([sejumlah besar]) dengan bendera biner dihidupkan, tapi saya agak tidak terbiasa dengan MySQL, dan tidak tahu apakah perbaikan seperti itu masuk akal.

Brian
sumber
3
Post-mortem: Solusi RichieHindle menyelesaikan masalah dan tidak memperkenalkan masalah tambahan apa pun saat itu sedang berjalan. Itu mungkin sedikit peretasan, tetapi berhasil, dan memungkinkan saya untuk menghindari tangan saya kotor dengan perangkat lunak pihak ke-3 yang tidak saya mengerti sepenuhnya. Pada titik ini, kami telah memperbarui ke versi yang lebih baru dari perangkat lunak / skema yang menangani semua masalah penyandian ini dengan benar (dan cukup baru sehingga benar-benar didukung), menjadikan peretasan tidak perlu.
Brian

Jawaban:

43

"\xE4\xC5\xCC\xC9\xD3\xD8"tidak valid UTF-8. Diuji menggunakan Python:

>>> "\xE4\xC5\xCC\xC9\xD3\xD8".decode("utf-8")
...
UnicodeDecodeError: 'utf8' codec can't decode bytes in position 0-2: invalid data

Jika Anda mencari cara untuk menghindari kesalahan decoding dalam database, pengkodean cp1252 (alias "Windows-1252" alias "Windows Western European") adalah pengkodean yang paling permisif - setiap nilai byte adalah titik kode yang valid.

Tentu saja itu tidak akan memahami UTF-8 asli lagi, atau pengkodean non-cp1252 lainnya, tapi sepertinya Anda tidak terlalu khawatir tentang itu?

RichieHindle
sumber
4
Apa yang sebenarnya Anda maksud dengan, "Tentu saja tidak akan memahami UTF-8 asli lagi?"
Brian
5
@Brian: Jika Anda memberi tahu Anda memberikannya cp1252, dan Anda benar-benar memberikannya UTF-8 untuk, katakanlah café, itu akan salah menafsirkan sebagai café. Itu tidak akan crash, tetapi itu akan salah paham karakter bit-tinggi.
RichieHindle
3
@ Richie: Basis data dapat dengan senang hati memanggil data apa pun yang diinginkannya, tetapi jika kode php yang mengambilnya memasukkannya ke dalam sebuah string, itu tidak akan membuat banyak perbedaan ... bukan? Saya tidak melihat persis di mana kurangnya pemahaman tentang UTF-8 berdampak.
Brian
7
@ Brian: Tidak, kamu benar. Waktu yang akan membuat perbedaan akan berada di dalam database, misalnya jika Anda menggunakan klausa ORDER BY dalam SQL Anda - pengurutan akan menjadi miring ketika Anda memiliki karakter non-ASCII.
RichieHindle
11
Hapus centang jawaban ini sebagai solusi, menyembunyikan kesalahan bukanlah solusi apa pun. Lepaskan lampu terlalu panas dari mobil Anda dan Anda akan melihat.
David Vartanian
133

Saya tidak akan menyarankan jawaban Richies, karena Anda mengacaukan data di dalam database. Anda tidak akan memperbaiki masalah Anda tetapi mencoba untuk "menyembunyikan" itu dan tidak dapat melakukan operasi database penting dengan data yang retak.

Jika Anda menjumpai kesalahan ini, data yang Anda kirimkan tidak disandikan UTF-8, atau koneksi Anda tidak UTF-8. Pertama, verifikasi, bahwa sumber data (file, ...) benar - benar adalah UTF-8.

Kemudian, periksa koneksi database Anda, Anda harus melakukan ini setelah menghubungkan:

SET NAMES 'utf8';
SET CHARACTER SET utf8;

Selanjutnya, verifikasi bahwa tabel tempat data disimpan memiliki set karakter utf8:

SELECT
  `tables`.`TABLE_NAME`,
  `collations`.`character_set_name`
FROM
  `information_schema`.`TABLES` AS `tables`,
  `information_schema`.`COLLATION_CHARACTER_SET_APPLICABILITY` AS `collations`
WHERE
  `tables`.`table_schema` = DATABASE()
  AND `collations`.`collation_name` = `tables`.`table_collation`
;

Terakhir, periksa pengaturan basis data Anda:

mysql> show variables like '%colla%';
mysql> show variables like '%charac%';

Jika sumber, transportasi, dan tujuan UTF-8, masalah Anda hilang;)

nico gawenda
sumber
1
@Kariem: Ini aneh, karena pengaturan ini dicakup oleh perintah SET NAMES, yang setara dengan memanggil SET character_set_client, SET character_set_results, SET character_set_connection dev.mysql.com/doc/refman/5.1/id/charset-connection.html
nico gawenda
2
Perintah kedua seharusnya SET CHARACTER SET utf8(bukan CHARACTER_SET)
Coder
6
Meskipun jawaban ini membantu menyelidiki masalah, jawaban itu tidak menjawab apa yang harus dilakukan untuk memperbaikinya. Saya melihat "latin1" bukannya "utf-8".
Vanuan
2
jawaban ini sangat bagus untuk menjelaskan masalah tetapi sangat miskin dalam merinci solusi (yang diminta OP). @nicogawenda: Apa saja pertanyaan SQL yang harus dijalankan untuk memperbaiki masalah? Bagaimana cara memperbaiki semua data yang sudah ada?
Clint Eastwood
1
"Jika sumber, transportasi, dan tujuan adalah UTF-8, masalah Anda sudah hilang;)" itu adalah trik untuk saya
suarsenegger
80

Tipe MySQL utf-8 sebenarnya tidak tepat utf-8 - ia hanya menggunakan hingga tiga byte per karakter dan hanya mendukung Basic Multilingual Plane (yaitu tanpa Emoji, no astral plane, dll.).

Jika Anda perlu menyimpan nilai dari bidang Unicode yang lebih tinggi, Anda memerlukan pengkodean utf8mb4 .

moeffju
sumber
9
Saya pikir ini mungkin perbaikan terbaik. Tingkatkan ke 5.5 dan ganti utf8 dengan utf8mb4 dalam jawaban di atas. Saya memasukkan data utf8 dari Twitter yang memiliki emoji atau karakter lain yang membutuhkan 4 byte.
rmarscher
Mari kita asumsikan kita tidak akan memperbarui ke 5.5. Bagaimana cara kita menekan kesalahan?
Pengguna
Saya menggulir terlalu jauh untuk jawaban yang paling berguna ini
handheldblender
1
10 tahun sejak pertanyaan awal. Perlu diketahui bahwa pengkodean utf8 MySQL tidak tepat utf8. Gunakan utf8mb4! Hal yang sama berlaku untuk MariaDB. Kalau tidak, Anda tidak akan memiliki air mata sukacita 😂
Liam
51

Tabel dan bidang memiliki penyandian yang salah; namun, Anda dapat mengubahnya menjadi UTF-8.

ALTER TABLE logtest CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;

ALTER TABLE logtest DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

ALTER TABLE logtest CHANGE title title VARCHAR(100) CHARACTER SET utf8 COLLATE utf8_general_ci;
Jiayu Wang
sumber
1
Saya pikir ini adalah jawaban yang benar. Saya punya dua tabel memiliki format varchar utf8 masing-masing. salah satunya mendapat kesalahan, yang lain baik-baik saja. bahkan saya pengguna 'perbarui pilih' membuat salinan dari kolom 'baik' utf8 ke tabel lain, kesalahan yang sama terjadi. Itu karena dua tabel dibuat dalam versi MySQL yang berbeda.
AiShiguang
Iya! Itu juga salah konfigurasi dari tabel database saya. Saya pikir jawaban ini harus yang benar. Masalah saya adalah susunan yang dipilih adalah utf8_unicode_ci, bukan utf8_general_ci. Terima kasih :)
jprivillaso
2
Apa jawaban ini di sini, harus di atas
Sagun Shrestha
1
ini membantu, ini memberi tahu Anda apa yang harus dicoba, alih-alih apa yang salah.
Victor Di
Terima kasih! Itu hanya banyak membantu saya, saya telah mengubah semut meja kolokasi saya pikir itu harus tetapi ladang masih ascii kolasi ...
Radu
25

Saya memecahkan masalah ini hari ini dengan mengubah kolom ke tipe 'LONGBLOB' yang menyimpan byte mentah alih-alih karakter UTF-8.

Satu-satunya kelemahan dari melakukan ini adalah Anda harus mengurus pengodean sendiri. Jika satu klien aplikasi Anda menggunakan pengkodean UTF-8 dan yang lain menggunakan CP1252, Anda mungkin mengirim email Anda dengan karakter yang salah. Untuk menghindari hal ini, selalu gunakan pengkodean yang sama (misalnya UTF-8) di semua aplikasi Anda .

Rujuk ke halaman ini http://dev.mysql.com/doc/refman/5.0/en/blob.html untuk perincian lebih lanjut tentang perbedaan antara TEXT / LONGTEXT dan BLOB / LONGBLOB. Ada juga banyak argumen lain di web yang membahas keduanya.

frankshaka
sumber
1
Solusi ini tampaknya cara termudah untuk pergi. Saya mencoba beberapa pengkodean lain tanpa hasil.
Simeon Abolarinwa
10

Pertama periksa apakah default_character_set_name Anda adalah utf8.

SELECT default_character_set_name FROM information_schema.SCHEMATA S WHERE schema_name = "DBNAME";

Jika hasilnya tidak utf8 Anda harus mengonversi basis data Anda. Pada awalnya Anda harus menyimpan dump.

Untuk mengubah pengkodean set karakter ke UTF-8 untuk semua tabel dalam database yang ditentukan, ketikkan perintah berikut di baris perintah. Ganti DBNAME dengan nama basis data:

mysql --database=DBNAME -B -N -e "SHOW TABLES" | awk '{print "SET foreign_key_checks = 0; ALTER TABLE", $1, "CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci; SET foreign_key_checks = 1; "}' | mysql --database=DBNAME

Untuk mengubah pengkodean set karakter ke UTF-8 untuk database itu sendiri, ketik perintah berikut ini di prompt mysql >. Ganti DBNAME dengan nama basis data:

ALTER DATABASE DBNAME CHARACTER SET utf8 COLLATE utf8_general_ci;

Anda sekarang dapat mencoba lagi untuk menulis karakter utf8 ke dalam basis data Anda. Solusi ini membantu saya ketika saya mencoba mengunggah 200000 baris file csv ke dalam database saya.

Babacar Gningue
sumber
8

Secara umum, ini terjadi ketika Anda memasukkan string ke kolom dengan pengkodean / pengumpulan yang tidak kompatibel.

Saya mendapatkan kesalahan ini ketika saya memiliki TRIGGER, yang mewarisi susunan server untuk beberapa alasan. Dan default mysql adalah (setidaknya pada Ubuntu) latin-1 dengan susunan Swedia. Meskipun saya memiliki database dan semua tabel diatur ke UTF-8, saya belum mengaturnyamy.cnf :

/etc/mysql/my.cnf:

[mysqld]
character-set-server=utf8
default-character-set=utf8

Dan ini harus mencantumkan semua pemicu dengan utf8- *:

select TRIGGER_SCHEMA, TRIGGER_NAME, CHARACTER_SET_CLIENT, COLLATION_CONNECTION, DATABASE_COLLATION from information_schema.TRIGGERS

Dan beberapa variabel yang terdaftar oleh ini juga harus memiliki utf-8- * (tidak ada latin-1 atau pengkodean lainnya):

show variables like 'char%';
Ondra Žižka
sumber
6

Meskipun susunan Anda diatur ke utf8_general_ci, saya menduga bahwa pengkodean karakter dari basis data, tabel atau bahkan mungkin berbeda.

ALTER TABLE tabale_name MODIFY COLUMN column_name VARCHAR(255)  
CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
Sameera Prasad Jayasinghe
sumber
5

Saya mendapat kesalahan serupa ( Incorrect string value: '\xD0\xBE\xDO\xB2. ...' for 'content' at row 1). Saya telah mencoba untuk mengubah set karakter kolom ke utf8mb4dan setelah itu kesalahannya berubah menjadi 'Data too long for column 'content' at row 1'.
Ternyata mysql menunjukkan kesalahan pada saya. Saya membalikkan set karakter kolom ke utf8dan mengubah tipe kolom menjadi MEDIUMTEXT. Setelah itu kesalahannya hilang.
Saya harap ini membantu seseorang.
By the way MariaDB dalam kasus yang sama (saya telah menguji INSERT yang sama di sana) hanya memotong teks tanpa kesalahan.

AVKurov
sumber
MySQL juga saya lelah banyak hal, menyadari mysql tidak mendukung 4 byte utf-8 uncoding pada versi ini dan sedang sekarat berusaha memahami apa yang menyebabkan ini. Mengubah jenis itu rupanya jawabannya, solusi langsung.
Liza
4

Kesalahan itu berarti bahwa Anda memiliki string dengan penyandian yang salah (mis. Anda mencoba memasukkan string yang disandikan ISO-8859-1 ke dalam kolom yang disandikan UTF-8), atau kolom tidak mendukung data yang Anda coba masukkan.

Dalam prakteknya, masalah yang terakhir disebabkan oleh implementasi MySQL UTF-8 yang hanya mendukung karakter UNICODE yang membutuhkan 1-3 byte ketika direpresentasikan dalam UTF-8. Lihat "Nilai string salah" ketika mencoba memasukkan UTF-8 ke MySQL melalui JDBC? untuk detail.

Mikko Rantalainen
sumber
2

Solusi bagi saya ketika berlari ke nilai string salah ini: '\ xF8' untuk kesalahan kolom menggunakan scriptcase adalah untuk memastikan bahwa basis data saya diatur untuk utf8 general ci dan demikian juga pengumpulan lapangan saya. Kemudian ketika saya melakukan impor data file csv saya memuat csv ke UE Studio kemudian menyimpannya diformat sebagai utf8 dan Voila! Ini berfungsi seperti pesona, 29.000 catatan di sana tidak ada kesalahan. Sebelumnya saya mencoba untuk mengimpor csv yang dibuat excel.

otak utama
sumber
2

Saya telah mencoba semua solusi di atas (yang semuanya membawa poin valid), tetapi tidak ada yang berhasil untuk saya.

Sampai saya menemukan bahwa pemetaan bidang tabel MySQL saya di C # menggunakan tipe yang salah: MySqlDbType.Blob . Saya mengubahnya ke MySqlDbType.Text dan sekarang saya bisa menulis semua simbol UTF8 yang saya inginkan!

ps Bidang tabel MySQL saya adalah tipe "LongText". Namun, ketika saya membuat otomatis pemetaan bidang menggunakan perangkat lunak MyGeneration, secara otomatis mengatur jenis bidang sebagai MySqlDbType.Blob di C #.

Menariknya, saya telah menggunakan tipe MySqlDbType.Blob dengan karakter UTF8 selama berbulan-bulan tanpa kesulitan, sampai suatu hari saya mencoba menulis string dengan beberapa karakter tertentu di dalamnya.

Semoga ini bisa membantu seseorang yang berjuang untuk menemukan alasan kesalahan tersebut.

Ugnius Ramanauskas
sumber
1

Saya menambahkan biner sebelum nama kolom dan menyelesaikan kesalahan charset.

masukkan ke dalam nilai tableA (binary stringcolname1);

Richardhe2007
sumber
1

Hai saya juga mendapatkan kesalahan ini ketika saya menggunakan database online saya dari server godaddy saya pikir itu memiliki versi mysql 5.1 atau lebih. tetapi ketika saya lakukan dari server localhost saya (versi 5.7) itu baik-baik saja setelah itu saya membuat tabel dari server lokal dan disalin ke server online menggunakan mysql yog saya pikir masalahnya adalah dengan set karakter

Tangkapan layar Di Sini

Hashain Lakshan
sumber
1

Untuk memperbaiki kesalahan ini, saya memutakhirkan database MySQL saya ke utf8mb4 yang mendukung set karakter Unicode lengkap dengan mengikuti tutorial terperinci ini . Saya sarankan untuk melewatinya dengan hati-hati, karena ada beberapa gotcha (misalnya kunci indeks bisa menjadi terlalu besar karena pengkodean baru setelah itu Anda harus memodifikasi jenis bidang).

metakermit
sumber
1

Ada jawaban bagus di sini. Saya hanya menambahkan milik saya karena saya mengalami kesalahan yang sama tetapi ternyata menjadi masalah yang sama sekali berbeda. (Mungkin di permukaan sama, tetapi akar penyebabnya berbeda.)

Bagi saya kesalahan terjadi pada bidang berikut:

@Column(nullable = false, columnDefinition = "VARCHAR(255)")
private URI consulUri;

Ini akhirnya disimpan dalam database sebagai serialisasi biner URIkelas. Ini tidak memunculkan flag dengan pengujian unit (menggunakan H2) atau pengujian CI / integrasi (menggunakan MariaDB4j ), itu meledak dalam pengaturan seperti produksi kami. (Meskipun, begitu masalah dipahami, cukup mudah untuk melihat nilai yang salah dalam contoh MariaDB4j; itu hanya tidak meledakkan tes.) Solusinya adalah membangun mapper tipe khusus:

package redacted;

import javax.persistence.AttributeConverter;
import java.net.URI;
import java.net.URISyntaxException;

import static java.lang.String.format;

public class UriConverter implements AttributeConverter<URI, String> {
    @Override
    public String convertToDatabaseColumn(URI attribute) {
        return attribute.toString();
    }

    @Override
    public URI convertToEntityAttribute(String field) {
        try {
            return new URI(field);
        }
        catch (URISyntaxException e) {
            throw new RuntimeException(format("could not convert database field to URI: %s", field));
        }
    }
}

Digunakan sebagai berikut:

@Column(nullable = false, columnDefinition = "VARCHAR(255)")
@Convert(converter = UriConverter.class)
private URI consulUri;

Sejauh Hibernate terlibat, tampaknya ia memiliki banyak tipe pemetaan yang disediakan , termasuk untuk java.net.URL, tetapi tidak untuk java.net.URI(yang kami butuhkan di sini).

Sander Verhagen
sumber
1

Dalam kasus saya masalah itu diselesaikan dengan mengubah pengkodean kolom Mysql ke 'biner' (tipe data akan diubah secara otomatis menjadi VARBINARY). Mungkin saya tidak akan bisa memfilter atau mencari dengan kolom itu, tapi saya tidak perlu melakukannya.

WilyDen
sumber
1

Jika Anda memproses nilai dengan beberapa fungsi string sebelum menyimpan, pastikan fungsi tersebut dapat menangani karakter multibyte dengan benar. Fungsi string yang tidak dapat melakukan itu dan, katakanlah, mencoba untuk memotong mungkin membagi salah satu karakter multibyte tunggal di tengah, dan yang dapat menyebabkan situasi kesalahan string tersebut.

Dalam PHP misalnya, Anda harus beralih dari substrke mb_substr.

WoodrowShigeru
sumber
0

Dalam kasus saya, pertama saya bertemu '???' di situs web saya, lalu saya periksa set karakter Mysql yang bahasa latin sekarang, jadi saya mengubahnya menjadi utf-8, lalu saya restart proyek saya, kemudian saya mendapat kesalahan yang sama dengan Anda, kemudian saya menemukan bahwa saya lupa untuk mengubah charset database dan berubah menjadi utf-8, boom, itu berhasil.

acoder2013
sumber
0

Saya mencoba hampir setiap langkah yang disebutkan di sini. Tidak ada yang berhasil. Mariadb yang diunduh. Itu berhasil. Saya tahu ini bukan solusi namun ini mungkin membantu seseorang untuk mengidentifikasi masalah dengan cepat atau memberikan solusi sementara.

Server version: 10.2.10-MariaDB - MariaDB Server
Protocol version: 10
Server charset: UTF-8 Unicode (utf8)
cherankrish
sumber
0

Dalam kasus saya, Incorrect string value: '\xCC\x88'...masalahnya adalah o-umlaut dalam kondisi terurai. Pertanyaan-dan-jawaban ini membantu saya memahami perbedaan antara dan ö. Di PHP, perbaikannya bagi saya adalah dengan menggunakan perpustakaan Normalizer PHP . Misalnya Normalizer::normalize('o¨', Normalizer::FORM_C),.

MM.
sumber
-2

1 - Anda harus menyatakan dalam koneksi Anda propertie dari enconding UTF8. http://php.net/manual/en/mysqli.set-charset.php .

2 - Jika Anda menggunakan baris commando mysql untuk menjalankan skrip, Anda harus menggunakan flag, seperti: Cmd: C:\wamp64\bin\mysql\mysql5.7.14\bin\mysql.exe -h localhost -u root -P 3306 --default-character-set=utf8 omega_empresa_parametros_336 < C:\wamp64\www\PontoEletronico\PE10002Corporacao\BancoDeDadosModelo\omega_empresa_parametros.sql

Roger Gusmao
sumber