Saya mendapatkan kesalahan di bawah ini ketika mencoba melakukan pemilihan melalui prosedur tersimpan di MySQL.
Campuran collation ilegal (latin1_general_cs, IMPLICIT) dan (latin1_general_ci, IMPLICIT) untuk operasi '='
Ada gagasan tentang apa yang mungkin salah di sini?
Susunan tabel adalah latin1_general_ci
dan kolom di klausa where berada latin1_general_cs
.
Jawaban:
Hal ini umumnya disebabkan oleh perbandingan dua string pemeriksaan yang tidak kompatibel atau dengan mencoba memilih data pemeriksaan berbeda ke dalam kolom gabungan.
Klausa
COLLATE
memungkinkan Anda menentukan pemeriksaan yang digunakan dalam kueri.Misalnya,
WHERE
klausul berikut akan selalu memberikan kesalahan yang Anda posting:Solusi Anda adalah menentukan pemeriksaan bersama untuk dua kolom dalam kueri. Berikut adalah contoh yang menggunakan
COLLATE
klausa:SELECT * FROM table ORDER BY key COLLATE latin1_general_ci;
Opsi lainnya adalah menggunakan
BINARY
operator:Solusi Anda mungkin terlihat seperti ini:
SELECT * FROM table WHERE BINARY a = BINARY b;
atau,
SELECT * FROM table ORDER BY BINARY a;
sumber
COLLATE latin1_general_ci
yang menyebabkan kesalahan lain:COLLATION 'utf8_general_ci' is not valid for CHARACTER SET 'latin1''
- meskipun Anda tidak memiliki kolom dengan SET KARAKTER 'latin1'! Solusinya adalah dengan menggunakan cast BINARY. Lihat juga pertanyaan iniTL; DR
Ubah susunan salah satu (atau keduanya) string sehingga cocok, atau tambahkan
COLLATE
klausa ke ekspresi Anda.Apa sih "collation" ini?
Seperti yang didokumentasikan di bawah Kumpulan Karakter dan Kolasi secara Umum :
Contoh lebih lanjut diberikan di bawah Contoh Pengaruh Penyusunan .
Oke, tapi bagaimana MySQL memutuskan pemeriksaan mana yang akan digunakan untuk ekspresi tertentu?
Seperti yang didokumentasikan di bawah Collation of Expressions :
Jadi, apa yang dimaksud dengan "pemeriksaan campuran ilegal"?
Sebuah "gabungan pengumpulan ilegal" terjadi ketika sebuah ekspresi membandingkan dua string dari kumpulan yang berbeda tetapi memiliki pemaksaan yang sama dan aturan pemaksaan tidak dapat membantu menyelesaikan konflik. Ini adalah situasi yang dijelaskan di bawah poin ketiga dalam kutipan di atas.
Kesalahan khusus yang diberikan dalam pertanyaan,,
Illegal mix of collations (latin1_general_cs,IMPLICIT) and (latin1_general_ci,IMPLICIT) for operation '='
memberi tahu kita bahwa ada perbandingan kesetaraan antara dua string non-Unicode dengan koersibilitas yang sama. Lebih jauh lagi, ini memberi tahu kita bahwa collations tidak diberikan secara eksplisit dalam pernyataan tetapi tersirat dari sumber string (seperti metadata kolom).Itu semua sangat baik, tetapi bagaimana cara mengatasi kesalahan seperti itu?
Seperti yang disarankan oleh ekstrak manual yang dikutip di atas, masalah ini dapat diselesaikan dengan beberapa cara, di mana dua di antaranya masuk akal dan direkomendasikan:
Ubah susunan salah satu (atau keduanya) string sehingga cocok dan tidak ada lagi ambiguitas.
Bagaimana ini bisa dilakukan tergantung dari mana string itu berasal: Ekspresi literal mengambil pemeriksaan yang ditentukan dalam
collation_connection
variabel sistem; nilai dari tabel mengambil pemeriksaan yang ditentukan dalam metadata kolomnya.Paksa satu string agar tidak dapat dipaksakan.
Saya menghilangkan kutipan berikut dari atas:
Jadi, menambahkan
COLLATE
klausa ke salah satu string yang digunakan dalam perbandingan akan memaksa penggunaan susunan itu.Sementara yang lain akan menjadi praktik yang sangat buruk jika mereka dikerahkan hanya untuk mengatasi kesalahan ini:
Paksa salah satu (atau keduanya) string untuk memiliki nilai koersibilitas lain sehingga salah satunya diutamakan.
Penggunaan
CONCAT()
atauCONCAT_WS()
akan menghasilkan string dengan koersibilitas 1; dan (jika dalam rutinitas tersimpan) penggunaan parameter / variabel lokal akan menghasilkan string dengan koersibilitas 2.Ubah pengkodean salah satu (atau keduanya) string sehingga yang satu adalah Unicode dan yang lainnya bukan.
Ini dapat dilakukan melalui transcoding dengan ; atau melalui mengubah set karakter yang mendasari data (misalnya memodifikasi kolom, mengubah nilai literal, atau mengirimnya dari klien dalam pengkodean yang berbeda dan mengubah / menambahkan pengenal set karakter). Perhatikan bahwa mengubah pengkodean akan menimbulkan masalah lain jika beberapa karakter yang diinginkan tidak dapat dikodekan dalam kumpulan karakter baru.
CONVERT(expr USING transcoding_name)
character_set_connection
character_set_client
Ubah pengkodean salah satu (atau keduanya) string sehingga keduanya sama dan ubah satu string untuk menggunakan
_bin
pemeriksaan yang relevan .Metode untuk mengubah pengkodean dan penyusunan telah dirinci di atas. Pendekatan ini tidak akan banyak berguna jika seseorang benar-benar perlu menerapkan aturan pemeriksaan yang lebih canggih daripada yang ditawarkan oleh
_bin
pemeriksaan.sumber
Menambahkan 2c saya ke diskusi untuk calon karyawan Google.
Saya sedang menyelidiki masalah serupa di mana saya mendapatkan kesalahan berikut saat menggunakan fungsi khusus yang menerima parameter varchar:
Menggunakan kueri berikut:
mysql> show variables like "collation_database"; +--------------------+-----------------+ | Variable_name | Value | +--------------------+-----------------+ | collation_database | utf8_general_ci | +--------------------+-----------------+
Saya dapat mengetahui bahwa DB menggunakan utf8_general_ci , sedangkan tabelnya ditentukan menggunakan utf8_unicode_ci :
mysql> show table status; +--------------+-----------------+ | Name | Collation | +--------------+-----------------+ | my_view | NULL | | my_table | utf8_unicode_ci | ...
Perhatikan bahwa pandangan memiliki pemeriksaan NULL . Tampaknya tampilan dan fungsi memiliki definisi pemeriksaan meskipun kueri ini menunjukkan null untuk satu tampilan. Pemeriksaan yang digunakan adalah pemeriksaan DB yang ditentukan saat tampilan / fungsi dibuat.
Solusi yang menyedihkan adalah mengubah pemeriksaan db dan membuat ulang tampilan / fungsi untuk memaksa mereka menggunakan pemeriksaan saat ini.
Mengubah pemeriksaan db:
ALTER DATABASE mydb DEFAULT COLLATE utf8_unicode_ci;
Mengubah susunan tabel:
ALTER TABLE mydb CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;
Saya harap ini akan membantu seseorang.
sumber
show full columns from my_table;
alter table <TABLE> modify column <COL> varchar(255) collate utf8_general_ci;
SHOW session variables like '%collation%';
memberitahu Anda bahwa »collation_connection« adalah »utf8mb4_general_ci«? Lalu lariSET collation_connection = utf8mb4_unicode_ci
dulu.Terkadang berbahaya untuk mengonversi rangkaian karakter, khususnya pada database dengan data dalam jumlah besar. Menurut saya, opsi terbaik adalah menggunakan operator "biner":
sumber
Saya memiliki masalah yang sama, mencoba menggunakan prosedur FIND_IN_SET dengan variabel string .
SET @my_var = 'string1,string2'; SELECT * from my_table WHERE FIND_IN_SET(column_name,@my_var);
dan menerima kesalahan
Jawaban singkat:
Tidak perlu mengubah variabel collation_YYYY, cukup tambahkan pemeriksaan yang benar di sebelah deklarasi variabel Anda , yaitu
SET @my_var = 'string1,string2' COLLATE utf8_unicode_ci; SELECT * from my_table WHERE FIND_IN_SET(column_name,@my_var);
Jawaban panjang:
Saya pertama kali memeriksa variabel pemeriksaan:
mysql> SHOW VARIABLES LIKE 'collation%'; +----------------------+-----------------+ | Variable_name | Value | +----------------------+-----------------+ | collation_connection | utf8_general_ci | +----------------------+-----------------+ | collation_database | utf8_general_ci | +----------------------+-----------------+ | collation_server | utf8_general_ci | +----------------------+-----------------+
Lalu saya memeriksa susunan tabel:
mysql> SHOW CREATE TABLE my_table; CREATE TABLE `my_table` ( `id` int(11) NOT NULL AUTO_INCREMENT, `column_name` varchar(40) COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=125 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Ini berarti variabel saya dikonfigurasi dengan pemeriksaan default utf8_general_ci sementara tabel saya dikonfigurasi sebagai utf8_unicode_ci .
Dengan menambahkan perintah COLLATE di sebelah deklarasi variabel, pemeriksaan variabel cocok dengan pemeriksaan yang dikonfigurasi untuk tabel.
sumber
Anda dapat mencoba skrip ini , yang mengonversi semua database dan tabel Anda ke utf8.
sumber
Solusi jika literal terlibat.
Saya menggunakan Pentaho Data Integration dan tidak bisa menentukan sintaks sql. Menggunakan pencarian DB yang sangat sederhana memberikan kesalahan "Gabungan pengumpulan ilegal (cp850_general_ci, COERCIBLE) dan (latin1_swedish_ci, COERCIBLE) untuk operasi '='"
Kode yang dihasilkan adalah "PILIH DATA_DATE AS latest_DATA_DATE FROM hr_cc_normalised_data_date_v WHERE PSEUDO_KEY =?"
Singkat cerita, pencarian adalah untuk melihat dan ketika saya mengeluarkan
mysql> show full columns from hr_cc_normalised_data_date_v; +------------+------------+-------------------+------+-----+ | Field | Type | Collation | Null | Key | +------------+------------+-------------------+------+-----+ | PSEUDO_KEY | varchar(1) | cp850_general_ci | NO | | | DATA_DATE | varchar(8) | latin1_general_cs | YES | | +------------+------------+-------------------+------+-----+
yang menjelaskan dari mana 'cp850_general_ci' berasal.
Tampilan hanya dibuat dengan 'PILIH' X ', ......' Menurut literal manual seperti ini harus mewarisi kumpulan karakter dan pemeriksaan dari pengaturan server yang didefinisikan dengan benar sebagai 'latin1' dan 'latin1_general_cs' seperti ini jelas tidak terjadi saya memaksakannya dalam pembuatan tampilan
CREATE OR REPLACE VIEW hr_cc_normalised_data_date_v AS SELECT convert('X' using latin1) COLLATE latin1_general_cs AS PSEUDO_KEY , DATA_DATE FROM HR_COSTCENTRE_NORMALISED_mV LIMIT 1;
sekarang ini menunjukkan latin1_general_cs untuk kedua kolom dan kesalahan telah hilang. :)
sumber
MySQL benar-benar tidak menyukai kumpulan campuran kecuali jika dapat memaksa mereka ke yang sama (yang jelas tidak dapat dilakukan dalam kasus Anda). Tidak bisakah Anda memaksa pemeriksaan yang sama untuk digunakan melalui klausa COLLATE ? (atau
BINARY
pintasan yang lebih sederhana jika ada ...).sumber
Jika kolom yang bermasalah adalah "hash", pertimbangkan hal berikut ...
Jika "hash" adalah string biner, Anda harus benar-benar menggunakan
BINARY(...)
tipe data.Jika "hash" adalah string hex, Anda tidak perlu utf8, dan harus menghindarinya karena pemeriksaan karakter, dll. Misalnya, MySQL
MD5(...)
menghasilkan string hex 32-byte dengan panjang tetap.SHA1(...)
memberikan string hex 40-byte. Ini bisa disimpan ke dalamCHAR(32) CHARACTER SET ascii
(atau 40 untuk sha1).Atau, lebih baik lagi, simpan
UNHEX(MD5(...))
keBINARY(16)
. Ini memotong setengah ukuran kolom. (Namun, itu membuatnya agak tidak bisa dicetak.)SELECT HEX(hash) ...
Jika Anda ingin itu dapat dibaca.Membandingkan dua
BINARY
kolom tidak memiliki masalah pemeriksaan.sumber
Sangat menarik ... Sekarang, bersiaplah. Saya melihat semua solusi "tambahkan susunan" dan bagi saya, itu adalah perbaikan bantuan pita. Kenyataannya adalah desain database itu "buruk". Ya, perubahan standar dan hal-hal baru ditambahkan, bla bla, tetapi itu tidak mengubah fakta desain database yang buruk. Saya menolak untuk menggunakan rute menambahkan "collate" di seluruh pernyataan SQL hanya untuk membuat kueri saya berfungsi. Satu-satunya solusi yang berhasil untuk saya dan secara virtual menghilangkan kebutuhan untuk mengubah kode saya di masa depan adalah mendesain ulang database / tabel agar sesuai dengan kumpulan karakter yang akan saya jalani dan rangkul untuk masa depan jangka panjang. Dalam hal ini, saya memilih untuk menggunakan set karakter " utf8mb4 ".
Jadi solusi di sini ketika Anda menemukan pesan kesalahan "ilegal" adalah mendesain ulang database dan tabel Anda. Jauh lebih mudah dan lebih cepat daripada kedengarannya. Mengekspor data Anda dan mengimpornya kembali dari CSV mungkin tidak diperlukan. Ubah kumpulan karakter database dan pastikan semua kumpulan karakter tabel Anda cocok.
Gunakan perintah ini untuk memandu Anda:
SHOW VARIABLES LIKE "collation_database"; SHOW TABLE STATUS;
Sekarang, jika Anda menikmati menambahkan "collate" di sana-sini dan memperkuat kode Anda dengan force fulls "overrides", tebaklah.
sumber
Solusi di bawah ini berhasil untuk saya.
sumber
Solusi yang mungkin adalah mengonversi seluruh database ke UTF8 (lihat juga pertanyaan ini ).
sumber
Salah satu sumber masalah pemeriksaan adalah
mysql.proc
tabel. Periksa susunan prosedur dan fungsi penyimpanan Anda:SELECT p.db, p.db_collation, p.type, COUNT(*) cnt FROM mysql.proc p GROUP BY p.db, p.db_collation, p.type;
Perhatikan juga kolom
mysql.proc.collation_connection
danmysql.proc.character_set_client
.sumber
Jika Anda menginstal phpMyAdmin, Anda dapat mengikuti petunjuk yang diberikan di tautan berikut: https://mediatemple.net/community/products/dv/204403914/default-mysql-character-set-and-collation Anda harus mencocokkan susunan dari database dengan semua tabel, serta bidang tabel dan kemudian mengkompilasi ulang semua prosedur dan fungsi yang tersimpan. Dengan itu semuanya harus bekerja kembali.
sumber
Saya menggunakan
ALTER DATABASE mydb DEFAULT COLLATE utf8_unicode_ci;
, tetapi tidak berhasil.Dalam kueri ini:
Select * from table1, table2 where table1.field = date_format(table2.field,'%H');
Ini bekerja untuk saya:
Select * from table1, table2 where concat(table1.field) = date_format(table2.field,'%H');
Ya, hanya a
concat
.sumber
Kode ini perlu dimasukkan ke dalam Jalankan kueri / kueri SQL di database
SQL QUERY WINDOW
ALTER TABLE `table_name` CHANGE `column_name` `column_name` VARCHAR(128) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL;
Harap ganti nama_tabel dan nama_kolom dengan nama yang sesuai.
sumber