Campuran ilegal dari koleksi (utf8_unicode_ci, IMPLICIT) dan (utf8_general_ci, IMPLICIT) untuk operasi '='

160

Pesan kesalahan di MySql:

Illegal mix of collations (utf8_unicode_ci,IMPLICIT) and (utf8_general_ci,IMPLICIT) for operation '='

Saya telah melewati beberapa posting lain dan tidak dapat menyelesaikan masalah ini. Bagian yang terpengaruh adalah sesuatu yang mirip dengan ini:

CREATE TABLE users (
    userID INT UNSIGNED NOT NULL AUTO_INCREMENT,
    firstName VARCHAR(24) NOT NULL,
    lastName VARCHAR(24) NOT NULL,
    username VARCHAR(24) NOT NULL,
    password VARCHAR(40) NOT NULL,
    PRIMARY KEY (userid)
) ENGINE = INNODB CHARACTER SET utf8 COLLATE utf8_unicode_ci;

CREATE TABLE products (
    productID INT UNSIGNED NOT NULL AUTO_INCREMENT,
    title VARCHAR(104) NOT NULL,
    picturePath VARCHAR(104) NULL,
    pictureThumb VARCHAR(104) NULL,
    creationDate DATE NOT NULL,
    closeDate DATE NULL,
    deleteDate DATE NULL,
    varPath VARCHAR(104) NULL,
    isPublic TINYINT(1) UNSIGNED NOT NULL DEFAULT '1',
    PRIMARY KEY (productID)
) ENGINE = INNODB CHARACTER SET utf8 COLLATE utf8_unicode_ci;

CREATE TABLE productUsers (
    productID INT UNSIGNED NOT NULL,
    userID INT UNSIGNED NOT NULL,
    permission VARCHAR(16) NOT NULL,
    PRIMARY KEY (productID,userID),
    FOREIGN KEY (productID) REFERENCES products (productID) ON DELETE RESTRICT ON UPDATE NO ACTION,
    FOREIGN KEY (userID) REFERENCES users (userID) ON DELETE RESTRICT ON UPDATE NO ACTION
) ENGINE = INNODB CHARACTER SET utf8 COLLATE utf8_unicode_ci;

Prosedur tersimpan yang saya gunakan adalah ini:

CREATE PROCEDURE updateProductUsers (IN rUsername VARCHAR(24),IN rProductID INT UNSIGNED,IN rPerm VARCHAR(16))
BEGIN
    UPDATE productUsers
        INNER JOIN users
        ON productUsers.userID = users.userID
        SET productUsers.permission = rPerm
        WHERE users.username = rUsername
        AND productUsers.productID = rProductID;
END

Saya menguji dengan php, tetapi kesalahan yang sama diberikan dengan SQLyog. Saya juga telah menguji membuat ulang seluruh DB tetapi tidak baik.

Bantuan apa pun akan sangat dihargai.

Manatax
sumber

Jawaban:

220

Susunan standar untuk parameter prosedur tersimpan adalah utf8_general_cidan Anda tidak dapat mencampur susunan, sehingga Anda memiliki empat opsi:

Opsi 1 : tambahkan COLLATEke variabel input Anda:

SET @rUsername = aname COLLATE utf8_unicode_ci; -- COLLATE added
CALL updateProductUsers(@rUsername, @rProductID, @rPerm);

Opsi 2 : tambahkan COLLATEke WHEREklausa:

CREATE PROCEDURE updateProductUsers(
    IN rUsername VARCHAR(24),
    IN rProductID INT UNSIGNED,
    IN rPerm VARCHAR(16))
BEGIN
    UPDATE productUsers
        INNER JOIN users
        ON productUsers.userID = users.userID
        SET productUsers.permission = rPerm
        WHERE users.username = rUsername COLLATE utf8_unicode_ci -- COLLATE added
        AND productUsers.productID = rProductID;
END

Opsi 3 : tambahkan ke INdefinisi parameter:

CREATE PROCEDURE updateProductUsers(
    IN rUsername VARCHAR(24) COLLATE utf8_unicode_ci, -- COLLATE added
    IN rProductID INT UNSIGNED,
    IN rPerm VARCHAR(16))
BEGIN
    UPDATE productUsers
        INNER JOIN users
        ON productUsers.userID = users.userID
        SET productUsers.permission = rPerm
        WHERE users.username = rUsername
        AND productUsers.productID = rProductID;
END

Opsi 4 : ubah field itu sendiri:

ALTER TABLE users CHARACTER SET utf8 COLLATE utf8_general_ci;

Kecuali Anda perlu mengurutkan data dalam urutan Unicode, saya akan menyarankan mengubah semua tabel Anda untuk menggunakan utf8_general_cicollation, karena tidak memerlukan perubahan kode, dan akan mempercepat proses penyortiran.

UPDATE : utf8mb4 / utf8mb4_unicode_ci sekarang menjadi metode set / collation karakter yang disukai. utf8_general_ci disarankan, karena peningkatan kinerja dapat diabaikan. Lihat https://stackoverflow.com/a/766996/1432614

Ross Smith II
sumber
1
Hal ini juga memungkinkan untuk menambahkan COLLATE utf8_unicode_cike konstanta string: SET @EMAIL = '[email protected]' COLLATE utf8_unicode_ci;. Ini sangat berguna jika Anda menjalankan skrip dari konsol, di mana pengkodean default konsol berlaku untuk susunan string konstanta Anda.
gaborsch
Atau jatuhkan basis data dan buat baru dengan utf8_general_ci; pemeriksaan.
Oleksii Kyslytsyn
2
Untuk referensi di masa mendatang, jangan ubah semua tabel Anda menjadi utf8_general_ci kecuali Anda memahami perbedaan antara kedua pemeriksaan.
Manatax
1
@ GaborSch Menambahkan collate ke variabel string adalah solusi untuk saya, saya menulis jawaban terperinci tentang hal itu sebelum saya memperhatikan komentar Anda.
nkatsar
Saya mendapatkan kesalahan yang sama, kecuali (utf8mb4_unicode_ci, IMPLICIT)bukannya (utf8_unicode_ci, IMPLICIT). saya menggores data dari web menggunakan python, kemudian membuat file CSV dengan data yang tergores, yang kemudian saya proses dengan file PHP di server saya yang mengunggah data ke database saya. semua tabel / kolom MySQL saya disusun sebagai utf8mb4_unicode_ci. mungkin masalah ini muncul karena saya menyandikan data seperti utf8di python / csv?
oldboy
27

Saya menghabiskan setengah hari mencari jawaban untuk kesalahan identik "Campuran ilegal dari koleksi" dengan konflik antara utf8_unicode_ci dan utf8_general_ci.

Saya menemukan bahwa beberapa kolom dalam basis data saya tidak secara khusus disusun utf8_unicode_ci . Tampaknya mysql secara implisit menyusun kolom-kolom ini utf8_general_ci .

Secara khusus, menjalankan kueri 'SHOW CREATE TABLE table1' menghasilkan sesuatu seperti berikut:

| table1 | CREATE TABLE `table1` (
`id` int(11) NOT NULL,
`col1` varchar(4) CHARACTER SET utf8 NOT NULL,
`col2` int(11) NOT NULL,
PRIMARY KEY (`col1`,`col2`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |

Perhatikan baris 'col1' varchar (4) SET CHARACTER utf8 NOT NULL tidak memiliki collation yang ditentukan. Saya kemudian menjalankan kueri berikut:

ALTER TABLE table1 CHANGE col1 col1 VARCHAR(4) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL;

Ini menyelesaikan kesalahan "Campuran ilegal dari koleksi saya". Semoga ini bisa membantu orang lain di luar sana.

Nate Vaughan
sumber
7
Terima kasih. 'SHOW CREATE TABLE' adalah cara termudah untuk memahami & memperbaiki akar penyebab masalah.
joro
2
Perhatikan juga bahwa menentukan COLLATEuntuk seluruh tabel (yaitu ALTER TABLE table1 CHARSET utf8 COLLATE utf8_unicode_ci) tidak akan memperbaiki masalah , itu harus dilakukan untuk setiap kolom (bermasalah).
Skippy le Grand Gourou
6

Saya memiliki masalah yang sama, tetapi terpikir oleh saya di dalam prosedur, ketika param kueri saya diatur menggunakan variabel misalnya SET @value='foo'.

Apa yang menyebabkan ini tidak cocok collation_connectiondan pengumpulan Database. Diubah collation_connectionuntuk mencocokkan collation_databasedan masalah hilang. Saya pikir ini pendekatan yang lebih elegan daripada menambahkan COLLATE setelah param / value.

Singkatnya: semua koleksi harus cocok. Gunakan SHOW VARIABLESdan pastikan collation_connectiondan collation_databasecocokkan (juga periksa susunan tabel menggunakan SHOW TABLE STATUS [table_name]).

bpile
sumber
1
Masalah yang sama terjadi pada saya, saya menghindari mengubah variabel collation_YYY dengan mengatur pemeriksaan langsung dalam deklarasi variabel. SET @my_var = 'string1,string2' COLLATE utf8_unicode_ci;
nkatsar
5

Agak mirip dengan jawaban @bpile, kasus saya adalah pengaturan entri my.cnf collation-server = utf8_general_ci. Setelah saya menyadarinya (dan setelah mencoba semuanya di atas), saya dengan paksa mengganti database saya ke utf8_general_ci alih-alih utf8_unicode_ci dan hanya itu:

ALTER DATABASE `db` CHARACTER SET utf8 COLLATE utf8_general_ci;
Sebas
sumber
1
Sungguh aneh bahwa konfigurasi tersebar begitu banyak. Semua standar pemeriksaan harus ditetapkan di tempat yang sama.
Manatax
0

Dalam kasus saya sendiri, saya memiliki kesalahan berikut

Campuran ilegal dari koleksi (utf8_general_ci, IMPLICIT) dan (utf8_unicode_ci, IMPLICIT) untuk operasi '='

$ this-> db-> select ("users.username as matric_no, CONCAT (users.surname, '', users.first_name, '', users.last_name) sebagai nama lengkap") -> bergabung ('pengguna', 'pengguna .username = class_students.matric_no ',' left ') -> where (' class_students.session_id ', $ session) -> where (' class_students.level_id ', $ level) -> where (' class_students.dept_id ', $ dept );

Setelah berminggu-minggu pencarian google, saya perhatikan bahwa dua bidang yang saya bandingkan terdiri dari nama collation yang berbeda. Yang pertama yaitu nama pengguna adalah utf8_general_ci sedangkan yang kedua adalah utf8_unicode_ci jadi saya kembali ke struktur tabel kedua dan mengubah bidang kedua (matric_no) menjadi utf8_general_ci dan itu bekerja seperti pesona.

Teejaygenius
sumber
0

Meskipun menemukan sejumlah besar pertanyaan tentang masalah yang sama ( 1 , 2 , 3 , 4 ) saya belum pernah menemukan jawaban yang mempertimbangkan kinerja, bahkan di sini.

Meskipun beberapa solusi kerja telah diberikan, saya ingin melakukan pertimbangan kinerja.

EDIT: Terima kasih kepada Manatax untuk menunjukkan bahwa opsi 1 tidak mengalami masalah kinerja.

Menggunakan Opsi 1 dan 2 , alias pendekatan COLLATE cast, dapat menyebabkan potensi kemacetan, karena indeks apa pun yang ditentukan pada kolom tidak akan digunakan menyebabkan pemindaian penuh .

Meskipun saya tidak mencoba Opsi 3 , dugaan saya adalah ia akan mengalami konsekuensi yang sama dari opsi 1 dan 2.

Terakhir, Opsi 4 adalah opsi terbaik untuk tabel yang sangat besar bila memungkinkan. Maksud saya tidak ada penggunaan lain yang mengandalkan pemeriksaan asli.

Pertimbangkan permintaan yang disederhanakan ini:

SELECT 
    *
FROM
    schema1.table1 AS T1
        LEFT JOIN
    schema2.table2 AS T2 ON T2.CUI = T1.CUI
WHERE
    T1.cui IN ('C0271662' , 'C2919021')
;

Dalam contoh asli saya, saya memiliki lebih banyak bergabung. Tentu saja, table1 dan table2 memiliki susunan yang berbeda. Menggunakan operator susun untuk dilemparkan, itu akan menyebabkan indeks tidak digunakan.

Lihat penjelasan sql pada gambar di bawah ini.

Penjelasan Kueri Visual saat menggunakan cast COLLATE

Di sisi lain, opsi 4 dapat mengambil keuntungan dari kemungkinan indeks dan menyebabkan pertanyaan cepat.

Pada gambar di bawah ini, Anda dapat melihat kueri yang sama dijalankan setelah diterapkan Opsi 4 , alias mengubah susunan skema / tabel / kolom.

Penjelasan Kueri Visual setelah collation telah diubah, dan karenanya tanpa collate cast

Kesimpulannya, jika kinerja penting dan Anda dapat mengubah susunan tabel, pilih Opsi 4 . Jika Anda harus bertindak pada satu kolom, Anda dapat menggunakan sesuatu seperti ini:

ALTER TABLE schema1.table1 MODIFY `field` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
Raffaele
sumber
Terima kasih atas kontribusi Anda Raffaele, tetapi saya yakin opsi 1 akan menggunakan indeks, karena Anda tidak menggunakan tabel, tetapi nilai pembandingnya bahkan sebelum Anda meneruskannya ke SP.
Manatax
Terima kasih telah menunjukkannya. Itu kesalahan saya. Saya mengedit jawaban saya sesuai dengan itu.
Raffaele
0

Ini terjadi ketika kolom secara eksplisit diatur ke susunan berbeda atau susunan default berbeda dalam tabel yang ditanyakan.

jika Anda memiliki banyak tabel yang ingin Anda ubah susunan saat menjalankan kueri ini:

select concat('ALTER TABLE ', t.table_name , ' CONVERT TO CHARACTER 
SET utf8 COLLATE utf8_unicode_ci;') from (SELECT table_name FROM 
information_schema.tables where table_schema='SCHRMA') t;

ini akan menampilkan permintaan yang diperlukan untuk mengonversi semua tabel untuk menggunakan susunan yang benar per kolom

raam86
sumber
Ini juga terjadi ketika (seperti dalam kasus saya) susunan standar untuk SP berbeda dari susunan yang digunakan untuk tabel yang ditanyakan.
Manatax