การแก้ไขปัญหาข้อผิดพลาด“ การผสมที่ผิดพลาด” ใน mysql


210

ฉันได้รับข้อผิดพลาดด้านล่างเมื่อพยายามเลือกผ่านขั้นตอนการจัดเก็บใน MySQL

การรวมกันที่ผิดกฎหมาย (latin1_general_cs, IMPLICIT) และ (latin1_general_ci, IMPLICIT) สำหรับการดำเนินการ '='

ความคิดเกี่ยวกับสิ่งที่อาจจะผิดพลาดที่นี่?

การเปรียบเทียบของตารางมีและที่ของคอลัมน์ในข้อที่เป็นlatin1_general_cilatin1_general_cs


2
ฉันใช้ฐานข้อมูลที่หลากหลายเป็นระยะเวลานาน (ตั้งแต่ปี 1990) และการใช้การเรียงหน้าและการใช้งานร่วมกันโดย NySQL ปรากฏว่า "บ้า" ฐานข้อมูลแก้ปัญหาที่กำหนดตัวอักษร "ONE" สำหรับฐานข้อมูลจากนั้นขึ้นอยู่กับ โพรซีเดอร์การนำเข้า / ส่งออกเพื่อแปลงจาก / เป็นชุดอักขระเฉพาะที่ใช้โดยฐานข้อมูล โซลูชันที่เลือกไว้ของ Mysql นั้นขัดข้องเพราะกำลังผสม "ปัญหาของแอปพลิเคชัน" (การแปลงชุดอักขระ) กับปัญหาฐานข้อมูล (การใช้การเรียงชุด) ทำไมไม่ "ลบ" คุณลักษณะที่งี่เง่าและยุ่งยากจากฐานข้อมูลเพื่อให้สามารถใช้งานและควบคุมได้มากขึ้นโดย
Maurizio Pievaioli

คำตอบ:


216

โดยทั่วไปเกิดจากการเปรียบเทียบสองสายของการเปรียบเทียบที่เข้ากันไม่ได้หรือโดยพยายามเลือกข้อมูลของการเปรียบเทียบที่แตกต่างกันลงในคอลัมน์ที่รวมกัน

ส่วนคำสั่งCOLLATEอนุญาตให้คุณระบุการเปรียบเทียบที่ใช้ในแบบสอบถาม

ตัวอย่างเช่นWHEREข้อต่อไปนี้มักจะให้ข้อผิดพลาดที่คุณโพสต์:

WHERE 'A' COLLATE latin1_general_ci = 'A' COLLATE latin1_general_cs

โซลูชันของคุณคือการระบุการเปรียบเทียบที่ใช้ร่วมกันสำหรับสองคอลัมน์ภายในแบบสอบถาม นี่คือตัวอย่างที่ใช้ส่วนCOLLATEคำสั่ง:

SELECT * FROM table ORDER BY key COLLATE latin1_general_ci;

ตัวเลือกอื่นคือใช้BINARYโอเปอเรเตอร์:

BINARY str เป็นบทสรุปสำหรับนักแสดง (str AS BINARY)

โซลูชันของคุณอาจมีลักษณะเช่นนี้:

SELECT * FROM table WHERE BINARY a = BINARY b;

หรือ,

SELECT * FROM table ORDER BY BINARY a;

2
ขอบคุณ ที่จริงมันดูเหมือนว่าจะมีพฤติกรรมแปลก ๆ ในกรณีของฉัน เมื่อฉันเรียกใช้แบบสอบถามตามที่เป็นอยู่ผ่านเบราว์เซอร์แบบสอบถามจะดึงผลลัพธ์มาให้ฉัน แต่การใช้โพรซีเดอร์ที่เก็บไว้จะทำให้เกิดข้อผิดพลาดขึ้น
355562

5
ไบนารี่ดูเหมือนจะเป็นทางออกที่ดีที่สุดสำหรับฉัน มันอาจจะดีที่สุดสำหรับคุณเช่นกันหากคุณไม่ได้ใช้ฟิลเตอร์ที่ยุ่งยาก
Adam F

ฉันมีปัญหาเดียวกันวิธีที่ฉันแก้ปัญหานี้คือสร้างขึ้นใหม่ตั้งแต่ต้น ฉันลองเปลี่ยนการจัดเรียง แต่เมื่อฉันเข้าร่วมยังคงได้รับข้อผิดพลาดดังนั้นฉันจึงลองแบบนั้น cmiiw
Bobby Z

โปรดทราบว่ามีข้อผิดพลาดใน MariaDB ที่ใช้ COLLATE latin1_general_ci ซึ่งทำให้เกิดข้อผิดพลาดอื่น: COLLATION 'utf8_general_ci' is not valid for CHARACTER SET 'latin1''- แม้ว่าคุณจะไม่มีคอลัมน์ที่มีชุดอักขระ 'latin1'! ทางออกคือใช้การโยนแบบไบนารี ดูคำถามนี้ด้วย
Mel_T

154

TL; DR

เปลี่ยนการเปรียบเทียบหนึ่ง (หรือทั้งสอง) ของสตริงเพื่อให้ตรงกับหรืออื่นเพิ่มCOLLATEประโยคในการแสดงออกของคุณ


  1. อะไรคือ "การเปรียบเทียบ" นี้คืออะไร?

    ตามที่ระบุไว้ในชุดอักขระและการเปรียบเทียบโดยทั่วไป :

    ชุดตัวอักษรเป็นชุดของสัญลักษณ์และการเข้ารหัส การเปรียบเทียบคือชุดของกฎสำหรับการเปรียบเทียบอักขระในชุดอักขระ เรามาทำให้ความแตกต่างชัดเจนด้วยตัวอย่างของชุดตัวละครในจินตนาการ

    สมมติว่าเรามีตัวอักษรสี่ตัวอักษร: " A", " B", " a", " b" เราให้ตัวเลขแต่ละตัว:“ A” = 0,“ B” = 1,“ a” = 2,“ b” = 3. ตัวอักษร“ A” เป็นสัญลักษณ์, ตัวเลข 0 คือการเข้ารหัสสำหรับ“ A”, และการรวมกันของทั้งหมด สี่ตัวอักษรและการเข้ารหัสของพวกเขาเป็นชุดตัวอักษร

    สมมติว่าเราต้องการเปรียบเทียบค่าสตริงสองค่าคือ“ A” และ“ B” วิธีที่ง่ายที่สุดในการทำเช่นนี้คือดูที่การเข้ารหัส: 0 สำหรับ“ A” และ 1 สำหรับ“ B” เนื่องจาก 0 น้อยกว่า 1 เราจึงพูดว่า“ A” น้อยกว่า“ B” สิ่งที่เราเพิ่งทำไปคือการใช้การเปรียบเทียบกับชุดอักขระของเรา การเรียงเป็นชุดของกฎ (หนึ่งกฎเท่านั้นในกรณีนี้):“ เปรียบเทียบการเข้ารหัส” เราเรียกสิ่งนี้ว่าง่ายที่สุดของการเรียงที่เป็นไปได้ทั้งหมดไบนารีเปรียบเทียบ

    แต่ถ้าเราต้องการบอกว่าตัวอักษรตัวพิมพ์เล็กและตัวพิมพ์ใหญ่นั้นเทียบเท่ากัน จากนั้นเราจะมีกฎอย่างน้อยสองข้อ: (1) ปฏิบัติต่ออักษรตัวพิมพ์เล็ก“ a” และ“ b” เทียบเท่ากับ“ A” และ“ B”; (2) จากนั้นเปรียบเทียบการเข้ารหัส เราเรียกสิ่งนี้ว่าการเปรียบเทียบแบบตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ มันซับซ้อนกว่าการเปรียบเทียบแบบไบนารีเล็กน้อย

    ในชีวิตจริงชุดตัวละครส่วนใหญ่มีตัวละครมากมาย: ไม่ใช่แค่“ A” และ“ B” แต่เป็นตัวอักษรทั้งหมดบางครั้งตัวอักษรหลายตัวหรือระบบการเขียนแบบตะวันออกที่มีตัวละครหลายพันตัวพร้อมด้วยสัญลักษณ์พิเศษและเครื่องหมายวรรคตอนมากมาย นอกจากนี้ในชีวิตจริงการจัดเรียงส่วนใหญ่มีกฎมากมายไม่เพียง แต่จะแยกความแตกต่างของตัวอักษร แต่ยังแยกความแตกต่างของสำเนียง (“ สำเนียง” เป็นเครื่องหมายที่ติดอยู่กับตัวละครเช่นเดียวกับในภาษาเยอรมัน” Ö”) และสำหรับตัวละครหลายตัว การแมป (เช่นกฎที่“ Ö” =“ OE” ในหนึ่งในสองการเปรียบเทียบภาษาเยอรมัน)

    ตัวอย่างเพิ่มเติมให้ไว้ภายใต้ตัวอย่างของผลของการเรียงหน้า

  2. โอเค แต่ MySQL ตัดสินใจอย่างไรว่าจะใช้การเรียงหน้าแบบใดสำหรับนิพจน์ที่ระบุ

    ตามที่ระบุไว้ภายใต้การจัดเรียงของนิพจน์ :

    ในงบส่วนใหญ่เป็นที่ชัดเจนว่าการเปรียบเทียบ MySQL ใช้เพื่อแก้ไขการดำเนินการเปรียบเทียบคืออะไร ตัวอย่างเช่นในกรณีต่อไปนี้ควรมีความชัดเจนว่าการเปรียบเทียบคือการเปรียบเทียบของคอลัมน์charset_name:

    SELECT x FROM T ORDER BY x;
    SELECT x FROM T WHERE x = x;
    SELECT DISTINCT x FROM T;

    อย่างไรก็ตามด้วยตัวถูกดำเนินการหลายตัวอาจมีความกำกวม ตัวอย่างเช่น:

    SELECT x FROM T WHERE x = 'Y';

    การเปรียบเทียบควรใช้การเปรียบเทียบของคอลัมน์xหรือของตัวอักษรสตริง'Y'? ทั้งคู่xและ'Y'มีการเปรียบเทียบดังนั้นการเรียงลำดับใดที่มีความสำคัญกว่า

    SQL มาตรฐานจะแก้ไขคำถามดังกล่าวโดยใช้สิ่งที่เคยเรียกว่า "การข่มขู่" กฎ

    [ ลบ ]

    MySQL ใช้ค่า coercibility กับกฎต่อไปนี้เพื่อแก้ไขความกำกวม:

    • ใช้การเปรียบเทียบที่มีค่าความรุนแรงน้อยที่สุด

    • หากทั้งสองฝ่ายมีการข่มขู่เหมือนกันดังนั้น:

      • หากทั้งสองฝ่ายเป็น Unicode หรือทั้งสองข้างไม่ใช่ Unicode นั่นเป็นข้อผิดพลาด

      • หากด้านใดด้านหนึ่งมีชุดอักขระ Unicode และอีกด้านหนึ่งมีชุดอักขระที่ไม่ใช่ Unicode ด้านที่ชนะชุดอักขระ Unicode จะเป็นฝ่ายชนะและการแปลงชุดอักขระอัตโนมัติจะใช้กับด้านที่ไม่ใช่ Unicode ตัวอย่างเช่นคำสั่งต่อไปนี้จะไม่ส่งคืนข้อผิดพลาด:

        SELECT CONCAT(utf8_column, latin1_column) FROM t1;

        ก็จะส่งกลับผลที่มีชุดตัวอักษรของและการเปรียบเทียบเช่นเดียวกับutf8 utf8_columnค่าของlatin1_columnจะถูกแปลงเป็นอัตโนมัติutf8ก่อนทำการเชื่อมต่อ

      • สำหรับการดำเนินการที่มีตัวถูกดำเนินการจากชุดอักขระเดียวกัน แต่การผสม_bincollation และ a _ciหรือ_cscollation นั้น_binจะใช้ collation สิ่งนี้คล้ายกับวิธีที่การดำเนินการที่ผสมสตริงที่ไม่ใช่ไบนารี่และไบนารีประเมินตัวถูกดำเนินการเป็นสตริงไบนารียกเว้นว่าจะใช้สำหรับการเปรียบเทียบมากกว่าประเภทข้อมูล

  3. ดังนั้น "การรวมกันที่ผิดกฎหมายของการผสม" คืออะไร?

    "การผสมกันที่ผิดกฎหมาย" เกิดขึ้นเมื่อนิพจน์เปรียบเทียบสองสายของการเปรียบเทียบที่แตกต่างกัน แต่มีการข่มขู่เท่ากันและกฎการข่มขู่ไม่สามารถช่วยแก้ไขความขัดแย้งได้ เป็นสถานการณ์ที่อธิบายภายใต้สัญลักษณ์แสดงหัวข้อย่อยที่สามในใบเสนอราคาข้างต้น

    ข้อผิดพลาดเฉพาะที่เกิดขึ้นในคำถามIllegal mix of collations (latin1_general_cs,IMPLICIT) and (latin1_general_ci,IMPLICIT) for operation '='บอกเราว่ามีการเปรียบเทียบความเท่าเทียมกันระหว่างสองสายอักขระที่ไม่ใช่ Unicode ที่มีการข่มขู่เท่ากัน นอกจากนี้ยังบอกเราว่าการเปรียบเทียบไม่ได้ให้ไว้อย่างชัดเจนในคำสั่ง แต่ค่อนข้างจะบอกเป็นนัยจากแหล่งที่มาของสตริง (เช่นข้อมูลเมตาของคอลัมน์)

  4. ทั้งหมดนี้เป็นสิ่งที่ดีมาก แต่จะแก้ไขข้อผิดพลาดดังกล่าวได้อย่างไร

    เนื่องจากสารสกัดด้วยตนเองที่เสนอมาข้างต้นแนะนำปัญหานี้สามารถแก้ไขได้หลายวิธีซึ่งสองวิธีนี้เหมาะสมและควรได้รับการแนะนำ:

    • เปลี่ยนการเรียงหนึ่ง (หรือทั้งสอง) ของสตริงเพื่อให้ตรงกับและไม่มีความกำกวมอีกต่อไป

      วิธีการนี้สามารถทำได้ขึ้นอยู่กับว่าสตริงมาจากไหน: การแสดงออกตามตัวอักษรใช้การเปรียบเทียบที่ระบุในcollation_connectionตัวแปรระบบ ค่าจากตารางใช้การเปรียบเทียบที่ระบุในข้อมูลเมตาของคอลัมน์

    • บังคับให้หนึ่งสายที่จะไม่ถูกบีบบังคับ

      ฉันละเว้นข้อความต่อไปนี้จากด้านบน:

      MySQL กำหนดค่าความน่าเชื่อถือดังนี้:

      • ส่วนCOLLATEคำสั่งที่ชัดเจนมี coercibility เป็น 0 (ไม่ coercible เลย)

      • การต่อกันของสองสายที่มีการเปรียบเทียบที่แตกต่างกันมีค่า coercibility เท่ากับ 1

      • การเรียงคอลัมน์หรือพารามิเตอร์รูทีนที่เก็บไว้หรือตัวแปรโลคัลมีค่า coercibility เป็น 2

      • “ ค่าคงที่ของระบบ” (สตริงที่ส่งคืนโดยฟังก์ชันเช่นUSER()หรือVERSION()) มีค่า coercibility เท่ากับ 3

      • การเรียงตัวอักษรมีค่า coercibility เท่ากับ 4

      • NULLหรือการแสดงออกที่ได้รับมาจากNULLมีการข่มขู่จาก 5

      ดังนั้นเพียงแค่เพิ่มส่วนCOLLATEคำสั่งหนึ่งในสตริงที่ใช้ในการเปรียบเทียบจะบังคับให้ใช้การเปรียบเทียบนั้น

    ในขณะที่คนอื่น ๆ จะใช้วิธีที่ไม่ดีอย่างร้ายแรงหากพวกเขาถูกปรับใช้เพียงเพื่อแก้ไขข้อผิดพลาดนี้:

    • บังคับให้หนึ่ง (หรือทั้งสอง) ของสตริงที่จะมีค่า coercibility อื่น ๆ เพื่อให้มีความสำคัญ

      การใช้CONCAT()หรือCONCAT_WS()จะส่งผลให้สตริงที่มี coercibility เป็น 1 และ (หากอยู่ในรูทีนที่เก็บไว้) การใช้พารามิเตอร์ / ตัวแปรโลคัลจะส่งผลให้เกิดสตริงที่มีการข่มขู่ 2

    • เปลี่ยนการเข้ารหัสของหนึ่ง (หรือทั้งสอง) ของสตริงเพื่อให้เป็น Unicode และอื่น ๆ ไม่ใช่

      นี้สามารถทำได้ผ่านการแปลงรหัสที่มี; หรือผ่านการเปลี่ยนชุดอักขระพื้นฐานของข้อมูล (เช่นการแก้ไขคอลัมน์การเปลี่ยนค่าตัวอักษรหรือส่งจากลูกค้าในการเข้ารหัสที่แตกต่างกันและการเปลี่ยน/ เพิ่มผู้แนะนำชุดอักขระ) โปรดทราบว่าการเปลี่ยนการเข้ารหัสจะทำให้เกิดปัญหาอื่น ๆ หากอักขระที่ต้องการบางตัวไม่สามารถเข้ารหัสในชุดอักขระใหม่ได้CONVERT(expr USING transcoding_name)character_set_connectioncharacter_set_client

    • เปลี่ยนการเข้ารหัสของหนึ่ง (หรือทั้งสอง) ของสตริงเพื่อให้เหมือนกันและเปลี่ยนหนึ่งสายเพื่อใช้การ_binเปรียบเทียบที่เกี่ยวข้อง

      วิธีการเปลี่ยนการเข้ารหัสและการเรียงมีรายละเอียดด้านบน วิธีการนี้จะใช้เพียงเล็กน้อยหากจำเป็นต้องใช้กฎการจัดเรียงขั้นสูงกว่า_binจริง ๆ


4
โปรดทราบว่า "การผสมที่ผิดกฎหมายของการรวมกัน" สามารถเกิดขึ้นได้เมื่อไม่มีความกำกวมในการเปรียบเทียบที่ควรใช้ แต่สตริงที่จะถูกบังคับจะต้องถูกแปลงเป็นการเข้ารหัสที่อักขระบางตัวไม่สามารถแสดงได้ ผมได้กล่าวถึงกรณีนี้ในคำตอบที่ก่อนหน้านี้
eggyal

5
คำตอบที่ดี อันนี้ควรจะเพิ่มขึ้นเพราะมันดำลงไปในสิ่งที่นักพัฒนาควรรู้จริง ๆ ; ไม่ใช่แค่วิธีแก้ไข แต่เข้าใจจริงๆว่าทำไมสิ่งต่าง ๆ จึงเกิดขึ้นในแบบที่พวกเขากำลังเกิดขึ้น
ทำเครื่องหมาย

ขอบคุณมากคุณสอนฉันวันนี้
briankip

66

เพิ่ม 2c ของฉันลงในการสนทนาสำหรับผู้ใช้ Google ในอนาคต

ฉันกำลังตรวจสอบปัญหาที่คล้ายกันซึ่งฉันได้รับข้อผิดพลาดต่อไปนี้เมื่อใช้ฟังก์ชันที่กำหนดเองที่ได้รับพารามิเตอร์ varchar:

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

ใช้แบบสอบถามต่อไปนี้:

mysql> show variables like "collation_database";
    +--------------------+-----------------+
    | Variable_name      | Value           |
    +--------------------+-----------------+
    | collation_database | utf8_general_ci |
    +--------------------+-----------------+

ฉันสามารถบอกได้ว่า DB กำลังใช้utf8_general_ciในขณะที่ตารางถูกกำหนดโดยใช้utf8_unicode_ci :

mysql> show table status;
    +--------------+-----------------+
    | Name         | Collation       |
    +--------------+-----------------+
    | my_view      | NULL            |
    | my_table     | utf8_unicode_ci |
    ...

ขอให้สังเกตว่ามุมมองที่มีการเปรียบเทียบNULL ปรากฏว่ามุมมองและฟังก์ชั่นมีคำจำกัดความการเปรียบเทียบแม้ว่าแบบสอบถามนี้จะแสดงค่าว่างสำหรับหนึ่งมุมมอง การเปรียบเทียบที่ใช้คือการเปรียบเทียบฐานข้อมูลที่กำหนดไว้เมื่อสร้างมุมมอง / ฟังก์ชั่น

วิธีแก้ปัญหาที่เศร้าก็คือเปลี่ยนทั้งการเรียง db และสร้างมุมมอง / ฟังก์ชั่นใหม่เพื่อบังคับให้พวกเขาใช้การจัดเรียงปัจจุบัน

  • การเปลี่ยนการจัดเรียงของ db:

    ALTER DATABASE mydb DEFAULT COLLATE utf8_unicode_ci;
  • การเปลี่ยนการเรียงตาราง:

    ALTER TABLE mydb CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;

ฉันหวังว่านี่จะช่วยให้ใครบางคน


12
การเปรียบเทียบอาจถูกตั้งค่าที่ระดับคอลัมน์ คุณสามารถดูได้ด้วย:show full columns from my_table;
Jonathan Tran

ขอบคุณ. ฉันเพิ่งลบสคีมาและสร้างใหม่ด้วยการเปรียบเทียบค่าเริ่มต้นที่ถูกต้องและนำเข้าใหม่ทุกอย่าง
JRun

1
@JonathanTran ขอขอบคุณ! ฉันมีชุดอักขระและชุดการเรียงในตารางทั้งหมดฐานข้อมูลและการเชื่อมต่อ แต่มันก็ยังให้ข้อผิดพลาด! การเปรียบเทียบไม่ได้ถูกกำหนดไว้ในคอลัมน์! ฉันแก้ไขด้วยalter table <TABLE> modify column <COL> varchar(255) collate utf8_general_ci;
Chloe

2
Sidenote สำหรับ googler ในอนาคต: แม้ว่าฐานข้อมูลของคุณตารางและเขตข้อมูลทั้งหมดจะมีการเปรียบเทียบที่เหมือนกันคุณต้องตรวจสอบให้แน่ใจว่าการเชื่อมต่อของคุณใช้การเปรียบเทียบที่เหมือนกัน ทุกอย่างมี» utf8mb4_unicode_ci « แต่SHOW session variables like '%collation%';บอกคุณว่า» collation_connection «คือ» utf8mb4_general_ci «? จากนั้นเรียกใช้SET collation_connection = utf8mb4_unicode_ciล่วงหน้า
pixelbrackets

ขอบคุณ! ใช้เวลาสักครู่เพื่อติดตามสิ่งนี้ ตารางไม่เพียง แต่จะต้องมีการเปรียบเทียบที่เหมือนกัน แต่ DB ยังทำเช่นกัน!
moto

15

บางครั้งการแปลงชุดอักขระอาจเป็นอันตรายโดยเฉพาะในฐานข้อมูลที่มีข้อมูลจำนวนมาก ฉันคิดว่าตัวเลือกที่ดีที่สุดคือใช้ตัวดำเนินการ "binary":

e.g : WHERE binary table1.column1 = binary table2.column1

10

ผมมีปัญหาที่คล้ายกันก็พยายามที่จะใช้ขั้นตอน FIND_IN_SET กับสตริงตัวแปร

SET @my_var = 'string1,string2';
SELECT * from my_table WHERE FIND_IN_SET(column_name,@my_var);

และได้รับข้อผิดพลาด

รหัสข้อผิดพลาด: 1267 การเปรียบเทียบที่ผิดกฎหมาย (utf8_unicode_ci, IMPLICIT) และ (utf8_general_ci, IMPLICIT) สำหรับการดำเนินการ 'find_in_set'

คำตอบสั้น ๆ :

ไม่จำเป็นต้องเปลี่ยนตัวแปร collation_YYYY ใด ๆ เพียงเพิ่มการเปรียบเทียบที่ถูกต้องถัดจากการประกาศตัวแปรของคุณเช่น

SET @my_var = 'string1,string2' COLLATE utf8_unicode_ci;
SELECT * from my_table WHERE FIND_IN_SET(column_name,@my_var);

คำตอบยาว:

ฉันก่อนตรวจสอบตัวแปรการเรียง:

mysql> SHOW VARIABLES LIKE 'collation%';
    +----------------------+-----------------+
    | Variable_name        | Value           |
    +----------------------+-----------------+
    | collation_connection | utf8_general_ci |
    +----------------------+-----------------+
    | collation_database   | utf8_general_ci |
    +----------------------+-----------------+
    | collation_server     | utf8_general_ci |
    +----------------------+-----------------+

จากนั้นฉันตรวจสอบการเปรียบเทียบตาราง:

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;

ซึ่งหมายความว่าตัวแปรของฉันถูกกำหนดค่าด้วยเปรียบเทียบค่าเริ่มต้นของutf8_general_ciขณะที่โต๊ะของเราได้รับการกำหนดค่าเป็นutf8_unicode_ci

โดยการเพิ่มคำสั่ง COLLATE ถัดจากการประกาศตัวแปรการเปรียบเทียบตัวแปรที่ตรงกับการเรียงที่กำหนดค่าสำหรับตาราง



2

วิธีแก้ปัญหาถ้ามีตัวอักษรเกี่ยวข้อง

ฉันกำลังใช้ Pentaho Data Integration และไม่ต้องระบุไวยากรณ์ของ sql การใช้การค้นหา DB ที่ง่ายมากทำให้เกิดข้อผิดพลาด "การผสมที่ผิดกฎหมาย (cp850_general_ci, COERCIBLE) และ (latin1_swedish_ci, COERCIBLE) สำหรับการดำเนินการ '='"

รหัสที่สร้างขึ้นคือ "SELECT DATA_DATE AS latest_DATA_DATE จาก hr_cc_normalised_data_date_v WHERE PSEUDO_KEY =?"

การตัดเรื่องให้สั้นลงการค้นหาคือการมองและเมื่อฉันออก

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  |     |
+------------+------------+-------------------+------+-----+

ซึ่งอธิบายว่า 'cp850_general_ci' มาจากไหน

มุมมองที่ถูกสร้างขึ้นด้วย 'SELECT' X ', ...... ' ตามตัวอักษรคู่มือเช่นนี้ควรสืบทอดชุดอักขระและการเรียงจากการตั้งค่าเซิร์ฟเวอร์ที่กำหนดอย่างถูกต้องเป็น 'latin1' และ 'latin1_general_cs' เช่นนี้ ชัดเจนไม่ได้เกิดขึ้นฉันถูกบังคับในการสร้างมุมมอง

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;

ตอนนี้มันแสดง latin1_general_cs สำหรับทั้งคอลัมน์และข้อผิดพลาดได้หายไป :)


1

MySQL ไม่ชอบการผสม collation ยกเว้นว่ามันจะบังคับพวกมันให้เหมือนกัน (ซึ่งไม่ชัดเจนในกรณีของคุณ) คุณไม่สามารถบังคับให้ใช้การเรียงหน้าเดียวกันผ่านประโยค COLLATE ได้หรือไม่ (หรือBINARYทางลัดที่ง่ายกว่าถ้ามี ... )


นี่เป็นเอกลักษณ์ของ MySQL หรือไม่? ระบบอื่น ๆ จะจัดการการรวมกันของการเปรียบเทียบที่เข้ากันไม่ได้ซึ่งมีลำดับความสำคัญเท่ากันอย่างเห็นได้ชัดอย่างไร
eggyal

ลิงก์ของคุณไม่ถูกต้อง
Benubird

1

หากคอลัมน์ที่คุณมีปัญหาคือ "แฮช" ให้พิจารณาสิ่งต่อไปนี้ ...

หาก "hash" เป็นสตริงไบนารีคุณควรใช้BINARY(...)ประเภทข้อมูลจริง ๆ

หาก "hash" เป็นสตริงเลขฐานสิบหกคุณไม่จำเป็นต้องใช้ utf8 และควรหลีกเลี่ยงเช่นนี้เนื่องจากการตรวจสอบอักขระ ฯลฯ ตัวอย่างเช่น MySQL MD5(...)ให้ผลตอบแทนสตริงฐานสิบหกแบบ 32 ไบต์ความยาวคงที่ SHA1(...)ให้สตริงฐานสิบหก 40 ไบต์ สามารถเก็บไว้ในCHAR(32) CHARACTER SET ascii(หรือ 40 สำหรับ sha1)

หรือดีกว่ายังเก็บเข้าUNHEX(MD5(...)) BINARY(16)วิธีนี้จะลดขนาดของคอลัมน์ลงครึ่งหนึ่ง (อย่างไรก็ตามทำให้ค่อนข้างไม่สามารถพิมพ์ได้) SELECT HEX(hash) ...หากคุณต้องการให้สามารถอ่านได้

การเปรียบเทียบสองBINARYคอลัมน์ไม่มีปัญหาการเปรียบเทียบ


1

น่าสนใจมาก ... ตอนนี้เตรียมตัวให้พร้อม ฉันดูที่โซลูชัน "เพิ่มเรียง" ทั้งหมดและสำหรับฉันนั่นคือการแก้ไขปัญหาของวงดนตรี ความจริงก็คือการออกแบบฐานข้อมูล "ไม่ดี" ใช่การเปลี่ยนแปลงมาตรฐานและสิ่งใหม่ ๆ จะถูกเพิ่มเข้ามา แต่มันไม่ได้เปลี่ยนความจริงในการออกแบบฐานข้อมูล ฉันปฏิเสธที่จะไปกับเส้นทางของการเพิ่ม "เรียง" ทั่วงบ SQL เพียงเพื่อให้แบบสอบถามของฉันทำงาน ทางออกเดียวที่เหมาะกับฉันและแทบจะไม่จำเป็นต้องปรับแต่งโค้ดของฉันในอนาคตคือการออกแบบฐานข้อมูล / ตารางใหม่เพื่อให้ตรงกับชุดอักขระที่ฉันจะอยู่ด้วยและยอมรับในอนาคตในระยะยาว ในกรณีนี้ฉันเลือกที่จะไปกับชุดอักขระ " utf8mb4 "

ดังนั้นทางออกที่นี่เมื่อคุณพบว่าข้อผิดพลาด "ผิดกฎหมาย" คือการออกแบบฐานข้อมูลและตารางของคุณ มันง่ายขึ้นและเร็วขึ้นแล้วมันฟังดู การส่งออกข้อมูลของคุณและการนำเข้าอีกครั้งจาก CSV อาจไม่จำเป็นต้องมีแม้แต่ เปลี่ยนชุดอักขระของฐานข้อมูลและตรวจสอบให้แน่ใจว่าชุดอักขระทั้งหมดของตารางของคุณตรงกัน

ใช้คำสั่งเหล่านี้เพื่อแนะนำคุณ:

SHOW VARIABLES LIKE "collation_database";
SHOW TABLE STATUS;

ตอนนี้ถ้าคุณสนุกกับการเพิ่ม "เรียง" ที่นี่และที่นั่นและเพิ่มรหัสของคุณด้วยกองกำลังที่เต็มไปด้วย "การแทนที่" ลองเดาดูสิ



0

อีกแหล่งที่มาของปัญหาที่มีการเปรียบเทียบคือmysql.procตาราง ตรวจสอบการจัดเรียงของโพรซีเดอร์และฟังก์ชันการเก็บรักษาของคุณ:

SELECT
  p.db, p.db_collation, p.type, COUNT(*) cnt
FROM mysql.proc p
GROUP BY p.db, p.db_collation, p.type;

ยังให้ความสนใจกับmysql.proc.collation_connectionและmysql.proc.character_set_clientคอลัมน์


0

ถ้าคุณมี phpMyAdmin ติดตั้งคุณสามารถปฏิบัติตามคำแนะนำที่ให้ไว้ในการเชื่อมโยงต่อไปนี้: https://mediatemple.net/community/products/dv/204403914/default-mysql-character-set-and-collationคุณมีเพื่อให้ตรงกับเรียง ของฐานข้อมูลที่มีของตารางทั้งหมดรวมถึงเขตข้อมูลของตารางจากนั้นคอมไพล์กระบวนงานและฟังก์ชันที่เก็บไว้ทั้งหมดใหม่อีกครั้ง ด้วยทุกสิ่งที่ควรจะทำงานอีกครั้ง


-1

ฉันใช้ALTER DATABASE mydb DEFAULT COLLATE utf8_unicode_ci;แต่ไม่ได้ผล

ในแบบสอบถามนี้:

Select * from table1, table2 where table1.field = date_format(table2.field,'%H');

งานนี้สำหรับฉัน:

Select * from table1, table2 where concat(table1.field) = date_format(table2.field,'%H');

concatใช่เพียง


ตรวจสอบการเรียงลำดับของตารางและคอลัมน์ของคุณ (แสดงสถานะตารางและแสดงคอลัมน์แบบเต็มจาก table1;) การใช้ฐานข้อมูลการแก้ไขจะไม่ทำงานหากตารางนั้นถูกสร้างขึ้นโดยมีการเปรียบเทียบที่ผิด
Ariel T

แก้ไขฐานข้อมูล mydb ค่าเริ่มต้น ... ทำงานให้ฉันดังนั้นอัปโหลด บางทีฉันอาจได้เปรียบเพราะฉันสามารถวางและสร้างฐานข้อมูลและโหลดจากการสำรองข้อมูลได้
tobixen

-2

รหัสนี้จะต้องใส่ในเรียกใช้แบบสอบถาม SQL / แบบสอบถามในฐานข้อมูล

SQL QUERY WINDOW

ALTER TABLE `table_name` CHANGE `column_name` `column_name`   VARCHAR(128) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL;

โปรดแทนที่ table_name และ column_name ด้วยชื่อที่เหมาะสม

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.