ฉันจะสร้างแบบสอบถาม SQL (MS SQL Server) ได้อย่างไรโดยที่ส่วนคำสั่ง "where" ไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่
SELECT * FROM myTable WHERE myField = 'sOmeVal'
ฉันต้องการให้ผลลัพธ์กลับมาโดยไม่สนใจคดี
ฉันจะสร้างแบบสอบถาม SQL (MS SQL Server) ได้อย่างไรโดยที่ส่วนคำสั่ง "where" ไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่
SELECT * FROM myTable WHERE myField = 'sOmeVal'
ฉันต้องการให้ผลลัพธ์กลับมาโดยไม่สนใจคดี
คำตอบ:
ในการกำหนดค่าเริ่มต้นของฐานข้อมูล SQL Server การเปรียบเทียบสตริงจะไม่คำนึงถึงขนาดตัวพิมพ์ หากฐานข้อมูลของคุณแทนที่การตั้งค่านี้ (ผ่านการใช้การเปรียบเทียบทางเลือก) คุณจะต้องระบุประเภทของการเปรียบเทียบที่จะใช้ในการสืบค้นของคุณ
SELECT * FROM myTable WHERE myField = 'sOmeVal' COLLATE SQL_Latin1_General_CP1_CI_AS
โปรดทราบว่าการจัดเรียงที่ฉันให้ไว้เป็นเพียงตัวอย่าง (แม้ว่ามันจะทำงานได้ดีสำหรับคุณมากกว่าก็ตาม) เค้าร่างอย่างละเอียดมากขึ้นของ collations SQL Server สามารถพบได้ที่นี่
UPPER
หรือLOWER
กรณีจากนั้นใช้LIKE
เพื่อค้นหา
โดยปกติการเปรียบเทียบสตริงจะไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่ หากฐานข้อมูลของคุณถูกกำหนดค่าให้เรียงตามตัวพิมพ์เล็กและใหญ่คุณต้องบังคับให้ใช้ตัวพิมพ์เล็กและใหญ่:
SELECT balance FROM people WHERE email = 'billg@microsoft.com'
COLLATE SQL_Latin1_General_CP1_CI_AS
ฉันพบวิธีแก้ปัญหาอื่นที่อื่น นั่นคือการใช้
upper(@yourString)
แต่ทุกคนที่นี่บอกว่าใน SQL Server มันไม่สำคัญหรอกเพราะมันไม่สนใจเคสอยู่ดี? ฉันค่อนข้างมั่นใจว่าฐานข้อมูลของเราคำนึงถึงขนาดตัวพิมพ์
คำตอบ 2 อันดับแรก (จากAdam RobinsonและAndrejs Cainikovs ) เป็นคำตอบที่ถูกต้องเนื่องจากใช้งานได้ในทางเทคนิค แต่คำอธิบายของพวกเขาผิดและอาจทำให้เข้าใจผิดได้ในหลาย ๆ กรณี ตัวอย่างเช่นแม้ว่าการSQL_Latin1_General_CP1_CI_AS
เปรียบเทียบจะทำงานในหลาย ๆ กรณี แต่ก็ไม่ควรถือว่าเป็นการเปรียบเทียบแบบไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่ที่เหมาะสม ในความเป็นจริงเนื่องจาก OP ทำงานในฐานข้อมูลที่มีการเปรียบเทียบตัวพิมพ์เล็กและใหญ่ (หรืออาจเป็นไบนารี) เราจึงทราบว่า OP ไม่ได้ใช้การเปรียบเทียบซึ่งเป็นค่าเริ่มต้นสำหรับการติดตั้งจำนวนมาก SQL_Latin1_General_CP1_CI_AS
โดยใช้ภาษาอังกฤษเป็นภาษา): แน่นอนว่า OP สามารถใช้SQL_Latin1_General_CP1_CS_AS
งานได้ แต่เมื่อทำงานกับไฟล์VARCHAR
ข้อมูลเป็นสิ่งสำคัญที่จะต้องไม่เปลี่ยนโค้ดเพจเนื่องจากอาจทำให้ข้อมูลสูญหายและถูกควบคุมโดยโลแคล / วัฒนธรรมของการจัดเรียง (เช่น Latin1_General vs French vs Hebrew เป็นต้น) โปรดดูจุด # 9 ด้านล่าง
อีกสี่คำตอบนั้นผิดองศาที่แตกต่างกัน
ฉันจะชี้แจงความเข้าใจผิดทั้งหมดที่นี่เพื่อให้ผู้อ่านสามารถตัดสินใจเลือกที่เหมาะสม / มีประสิทธิภาพมากที่สุด
ห้ามใช้UPPER()
. นั่นคืองานพิเศษที่ไม่จำเป็นอย่างสิ้นเชิง ใช้COLLATE
อนุประโยค. ต้องทำการเปรียบเทียบสตริงในทั้งสองกรณี แต่การใช้UPPER()
ยังต้องตรวจสอบทีละอักขระเพื่อดูว่ามีการแม็ปตัวพิมพ์ใหญ่หรือไม่จากนั้นจึงเปลี่ยน และคุณต้องทำทั้งสองด้าน การเพิ่มCOLLATE
เพียงแค่สั่งให้การประมวลผลสร้างคีย์การจัดเรียงโดยใช้ชุดของกฎที่แตกต่างจากที่เป็นไปตามค่าเริ่มต้น ใช้COLLATE
แน่นอนมีประสิทธิภาพมากขึ้น (หรือ "performant" ถ้าคุณชอบคำว่า :) กว่าการใช้UPPER()
เช่นการพิสูจน์ในการนี้สคริปต์ทดสอบ (บน Pastebin)
นอกจากนี้ยังมีปัญหาที่ระบุโดย @Ceisc ในคำตอบของ @ Danny:
ในบางภาษากรณีที่การแปลงไม่ได้ไป - กลับ เช่น LOWER (x)! = LOWER (บน (x))
ตัวพิมพ์ใหญ่ของตุรกี "İ" เป็นตัวอย่างทั่วไป
ไม่การจัดเรียงไม่ใช่การตั้งค่าทั้งฐานข้อมูลอย่างน้อยก็ไม่ใช่ในบริบทนี้ มีการเปรียบเทียบเริ่มต้นในระดับฐานข้อมูลและใช้เป็นค่าเริ่มต้นสำหรับคอลัมน์ที่เปลี่ยนแปลงและสร้างขึ้นใหม่ที่ไม่ระบุส่วนCOLLATE
คำสั่ง (ซึ่งเป็นไปได้ว่าความเข้าใจผิดทั่วไปนี้มาจากที่ใด) แต่จะไม่ส่งผลต่อการสืบค้นโดยตรงเว้นแต่คุณจะเป็น เปรียบเทียบลิเทอรัลสตริงและตัวแปรกับลิเทอรัลและตัวแปรสตริงอื่น ๆ หรือคุณกำลังอ้างอิงข้อมูลเมตาดาต้าระดับฐานข้อมูล
ไม่การเรียงลำดับไม่ใช่การค้นหา
การเรียงต่อกันเป็นไปตามเพรดิเคต (เช่นบางสิ่งที่ถูกดำเนินการบางอย่าง) หรือนิพจน์ไม่ใช่ต่อแบบสอบถาม และนี่เป็นจริงสำหรับข้อความค้นหาทั้งหมดไม่ใช่เฉพาะWHERE
อนุประโยค ซึ่งครอบคลุมถึง JOINs, GROUP BY, ORDER BY, PARTITION BY ฯลฯ
ไม่อย่าแปลงเป็นVARBINARY
(เช่นconvert(varbinary, myField) = convert(varbinary, 'sOmeVal')
) ด้วยเหตุผลต่อไปนี้:
_BIN2
ถ้าคุณกำลังใช้ SQL Server 2008 หรือใหม่กว่าอื่น ๆ ที่คุณไม่มีทางเลือก _BIN
แต่จะใช้หนึ่งที่ลงท้ายด้วย หากข้อมูลเป็นเช่นNVARCHAR
นั้นก็ไม่สำคัญว่าคุณจะใช้โลแคลใดเนื่องจากจะเหมือนกันทั้งหมดในกรณีนั้นจึงLatin1_General_100_BIN2
ใช้ได้เสมอ ถ้าข้อมูลVARCHAR
คุณต้องใช้สถานที่เดียวกันว่าข้อมูลที่เป็นอยู่ในปัจจุบัน (เช่นLatin1_General
, French
, Japanese_XJIS
ฯลฯ ) เพราะสถานที่เกิดเหตุเป็นตัวกำหนดหน้ารหัสที่ใช้และการเปลี่ยนแปลงโค้ดเพจสามารถแก้ไขข้อมูล (เช่นการสูญเสียข้อมูล)CONVERT()
มันจะใช้ค่าเริ่มต้น 30 อันตรายคือถ้าสตริงมีขนาดมากกว่า 30 ไบต์สตริงจะถูกตัดทอนอย่างเงียบ ๆ และคุณอาจได้ผลลัพธ์ที่ไม่ถูกต้องจากเพรดิเคตนี้ไม่LIKE
ไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่เสมอไป ใช้การเรียงของคอลัมน์ที่อ้างอิงหรือการเปรียบเทียบของฐานข้อมูลหากเปรียบเทียบตัวแปรกับสตริงลิเทอรัลหรือการเปรียบเทียบที่ระบุผ่านส่วนCOLLATE
คำสั่งเสริม
LCASE
ไม่ใช่ฟังก์ชัน SQL Server ดูเหมือนว่าจะเป็น Oracle หรือ MySQL หรืออาจเป็น Visual Basic?
เนื่องจากบริบทของคำถามกำลังเปรียบเทียบคอลัมน์กับสตริงลิเทอรัลทั้งการเปรียบเทียบอินสแตนซ์ (มักเรียกว่า "เซิร์ฟเวอร์") หรือการเปรียบเทียบฐานข้อมูลไม่มีผลกระทบโดยตรงที่นี่ การเรียงลำดับจะถูกเก็บไว้ในแต่ละคอลัมน์และแต่ละคอลัมน์สามารถมีการเปรียบเทียบที่แตกต่างกันได้และการเปรียบเทียบเหล่านั้นไม่จำเป็นต้องเหมือนกับการเปรียบเทียบเริ่มต้นของฐานข้อมูลหรือการเปรียบเทียบของอินสแตนซ์ แน่นอนว่าการเปรียบเทียบอินสแตนซ์เป็นค่าเริ่มต้นสำหรับสิ่งที่ฐานข้อมูลที่สร้างขึ้นใหม่จะใช้เป็นการเปรียบเทียบเริ่มต้นหากCOLLATE
ไม่ได้ระบุอนุประโยคเมื่อสร้างฐานข้อมูล และในทำนองเดียวกันการเปรียบเทียบเริ่มต้นของฐานข้อมูลคือสิ่งที่คอลัมน์ที่เปลี่ยนแปลงหรือสร้างขึ้นใหม่จะใช้หากCOLLATE
ไม่ได้ระบุอนุประโยค
คุณควรใช้การเปรียบเทียบแบบไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่ซึ่งเหมือนกับการเปรียบเทียบคอลัมน์ ใช้แบบสอบถามต่อไปนี้เพื่อค้นหาการเรียงของคอลัมน์ (เปลี่ยนชื่อตารางและชื่อสคีมา):
SELECT col.*
FROM sys.columns col
WHERE col.[object_id] = OBJECT_ID(N'dbo.TableName')
AND col.[collation_name] IS NOT NULL;
แล้วก็เปลี่ยนให้เป็น_CS
_CI
ดังนั้นก็จะกลายเป็นLatin1_General_100_CS_AS
Latin1_General_100_CI_AS
หากคอลัมน์กำลังใช้การเปรียบเทียบแบบไบนารี (ลงท้ายด้วย_BIN
หรือ_BIN2
) ให้ค้นหาการเปรียบเทียบที่คล้ายกันโดยใช้แบบสอบถามต่อไปนี้:
SELECT *
FROM sys.fn_helpcollations() col
WHERE col.[name] LIKE N'{CurrentCollationMinus"_BIN"}[_]CI[_]%';
ตัวอย่างเช่นสมมติว่ากำลังใช้คอลัมน์Japanese_XJIS_100_BIN2
ให้ทำสิ่งนี้:
SELECT *
FROM sys.fn_helpcollations() col
WHERE col.[name] LIKE N'Japanese_XJIS_100[_]CI[_]%';
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการจัดเรียงการเข้ารหัสและอื่น ๆ โปรดไปที่: ข้อมูลการจัดเรียง
ไม่ใช้เพียงอย่างเดียวLIKE
จะไม่ทำงาน LIKE
ค้นหาค่าที่ตรงกับรูปแบบที่คุณกำหนด ในกรณีนี้LIKE
จะพบเฉพาะข้อความ "sOmeVal" และไม่ใช่ "someval"
โซลูชันที่ใช้งานได้จริงคือการใช้LCASE()
ฟังก์ชัน LCASE('sOmeVal')
รับสตริงตัวพิมพ์เล็กของข้อความของคุณ: "someval" หากคุณใช้ฟังก์ชันนี้สำหรับการเปรียบเทียบทั้งสองด้านจะได้ผล:
SELECT * FROM myTable WHERE LCASE(myField) LIKE LCASE('sOmeVal')
คำสั่งจะเปรียบเทียบสตริงตัวพิมพ์เล็กสองตัวเพื่อให้ 'sOmeVal' ของคุณตรงกับสัญกรณ์อื่น ๆ ของ 'someval' (เช่น 'Someval', 'sOMEVAl' เป็นต้น)
LCASE()
อยู่ใน SQL Server (อย่างน้อยก็ไม่ใช่ที่ฉันเห็น) ฉันคิดว่าคำตอบนี้มีไว้สำหรับ RDBMS ที่แตกต่างกันอย่างสิ้นเชิง โปรดดูคำตอบของฉันสำหรับคำชี้แจงเกี่ยวกับการเปรียบเทียบสตริง
คุณสามารถบังคับให้พิจารณาตัวพิมพ์เล็กและใหญ่โดยหล่อเป็นตัวแปรแบบนั้น
SELECT * FROM myTable
WHERE convert(varbinary, myField) = convert(varbinary, 'sOmeVal')
คุณอยู่บนฐานข้อมูลใด ด้วย MS SQL Server เป็นการตั้งค่าทั่วทั้งฐานข้อมูลหรือคุณสามารถใช้งานต่อแบบสอบถามด้วยคีย์เวิร์ด COLLATE
WHERE
คำสั่งและจะมีผลต่อWHERE
ข้อทั้งหมดใช่ไหม