SQL Server ตัดค่า varchar โดยอัตโนมัติในการเปรียบเทียบเท่ากัน แต่ไม่เหมือนกับการเปรียบเทียบ


13

ฉันเจอพฤติกรรมที่น่าสนใจใน SQL Server (สังเกตในปี 2005 และ 2012) วันนี้ที่ฉันหวังว่าจะมีคนอธิบาย

เคียวรีที่ทำการเปรียบเทียบโดยใช้=ในเขตข้อมูล NVARCHAR จะละเว้นพื้นที่ต่อท้ายในสตริง (หรือตัดค่าอัตโนมัติก่อนการเปรียบเทียบ) แต่แบบสอบถามเดียวกันโดยใช้ตัวlikeดำเนินการไม่ได้เพิกเฉยพื้นที่ การจัดเรียงที่ใช้คือ Latin1_General_CI_AS ในปี 2012

พิจารณาซอ Fiddle นี้: http://sqlfiddle.com/#!6/72262/4

โปรดสังเกตว่าตัวlikeดำเนินการไม่ส่งคืนผลลัพธ์สำหรับสตริงช่องว่างต่อท้าย แต่ตัว=ดำเนินการทำ ทำไมนี้

คะแนนโบนัส: ฉันไม่สามารถทำซ้ำสิ่งนี้ในเขตข้อมูล VARCHAR ฉันคิดว่าพื้นที่จะได้รับการจัดการในลักษณะเดียวกันในทั้งสองประเภทข้อมูล - จริงหรือไม่


ฉันต้องการเขียนข้อ จำกัด การตรวจสอบว่ามีการตัดสตริง ฉันพบวิธีแก้ปัญหาซึ่งเป็นการตรวจสอบMyString+'x' = ltrim(rtrim(MyString))+'x'ตามที่แนะนำในบล็อกนี้
default.kramer

คำตอบ:


15

คำตอบเริ่มต้นของฉันแนะนำว่าการตั้งค่าสถานะ ANSI_PADDING เป็น OFF อาจเป็นการตำหนิสำหรับความแตกต่างในพฤติกรรม อย่างไรก็ตามสิ่งนี้ไม่ถูกต้อง ธงนี้มีผลต่อการจัดเก็บ แต่ไม่เปรียบเทียบความเท่าเทียมกัน

ความแตกต่างที่เกิดจากการใช้งานไมโครซอฟท์มาตรฐานของ SQL มาตรฐานระบุว่าเมื่อตรวจสอบความเท่าเทียมกันสตริงทั้งซ้ายและขวาของโอเปอเรเตอร์ความเท่าเทียมจะต้องถูกเสริมให้มีความยาวเท่ากัน สิ่งนี้จะอธิบายผลลัพธ์ต่อไปนี้:

insert into test_padding (varchar_clmn, nvarchar_clmn) values ('space ', 'nspace ')
go
-- equality for varchar column
select count(*) from test_padding where varchar_clmn = 'space' -- returns 1
select count(*) from test_padding where varchar_clmn = 'space ' -- returns 1
select count(*) from test_padding where varchar_clmn = 'space    ' --returns 1
-- equality for nvarchar column
select count(*) from test_padding where nvarchar_clmn = 'nspace' -- returns 1
select count(*) from test_padding where nvarchar_clmn = 'nspace ' -- returns 1
select count(*) from test_padding where nvarchar_clmn = 'nspace    ' --returns 1

ตัวดำเนินการ LIKE ไม่ได้บีบอัดตัวถูกดำเนินการ มันยังทำงานแตกต่างกันสำหรับVARCHARและNVARCHARประเภทคอลัมน์ :

-- likeness for varchar column
select count(*) from test_padding where varchar_clmn like 'space' -- returns 1
select count(*) from test_padding where varchar_clmn like 'space ' -- returns 1
select count(*) from test_padding where varchar_clmn like 'space    ' -- returns 0
-- likeness for nvarchar column
select count(*) from test_padding where nvarchar_clmn like 'nspace' -- returns 0
select count(*) from test_padding where nvarchar_clmn like 'nspace ' -- returns 1
select count(*) from test_padding where nvarchar_clmn like 'nspace    ' -- returns 0

ลักษณะการทำงานของตัวดำเนินการ LIKE สำหรับชนิด ASCII เป็น SQL Server เฉพาะ สำหรับประเภท Unicode เป็นไปตามมาตรฐาน ANSI


4

SQL เกิดขึ้นในยุคที่ภาษาการประมวลผลข้อมูลส่วนใหญ่ใช้ความยาวคงที่สำหรับทุกฟิลด์ / ตัวแปร การเว้นช่องข้อความอัตโนมัติพร้อมช่องว่างเพิ่มเติมก็เป็นส่วนหนึ่งของภาพนั้นเช่นกัน เพื่อให้สอดคล้องกับพฤติกรรมนั้นประเภทของ SQL CHAR ดั้งเดิมได้ถูกกำหนดไว้อย่างชัดเจนสำหรับตัวดำเนินการ '=' เพื่อละเว้นช่องว่างต่อท้าย (หากคุณพบว่าแปลก ๆ ให้ฉันดูกรณีที่น่าสนใจที่ช่องว่างต่อท้ายต่อท้ายข้อความมีความหมายทางธุรกิจจริงๆ )

SQL CHAR ประเภทต่าง ๆ มีวิวัฒนาการในทุกทิศทางตั้งแต่นั้นมา แต่ก็ไม่น่าเชื่อว่าบางประเภทข้อมูลที่ทันสมัยกว่านั้นยังคงสืบทอดคุณสมบัติบางอย่างจากรุ่นก่อนหน้าของประวัติศาสตร์


"แสดงกรณีที่น่าสนใจที่ช่องว่างต่อท้ายต่อท้ายข้อความนั้นมีความหมายทางธุรกิจจริง" - การจัดเก็บข้อมูลที่สำคัญช่องว่างเช่นเอาต์พุตคอนโซลดิบและการแยกส่วน XML ที่ไม่ปลอดภัยก่อน
Dai

1

ในเอกสารประกอบสำหรับLIKE (Transact-SQL) , Microsoft เขียน (ระเบิดของฉัน):

การจับคู่รูปแบบโดยใช้ LIKE

LIKE รองรับการจับคู่รูปแบบ ASCII และการจับคู่รูปแบบ Unicode เมื่ออาร์กิวเมนต์ทั้งหมด ... เป็นชนิดข้อมูลอักขระ ASCII จะทำการจับคู่รูปแบบ ASCII หากมีข้อโต้แย้งอย่างใดอย่างหนึ่งเป็นประเภทข้อมูล Unicode ข้อโต้แย้งทั้งหมดจะถูกแปลงเป็นการจับคู่รูปแบบ Unicode และ Unicode เมื่อคุณใช้ข้อมูล Unicode ... ด้วย LIKE ช่องว่างต่อท้ายจะมีความสำคัญ อย่างไรก็ตามสำหรับข้อมูลที่ไม่ใช่ Unicode ช่องว่างต่อท้ายไม่สำคัญ Unicode LIKE เข้ากันได้กับมาตรฐาน ISO ASCII LIKE เข้ากันได้กับ SQL Server รุ่นก่อนหน้า

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