คำถามเดิมคือ"ฉันจะตั้งค่าแบบสอบถามอย่างไร ... "
ขอผมพูดตรงนี้นะว่านี่ไม่ใช่คำตอบของคำถามเดิม มีการสาธิตในคำตอบที่ดีอื่น ๆ อยู่แล้ว
เมื่อทำตามที่กล่าวมาให้ทำเครื่องหมายคำตอบนี้แล้วลงคะแนนทำเครื่องหมายว่าไม่ใช่คำตอบ ... ทำทุกอย่างที่คุณเชื่อว่าถูกต้อง
ดูคำตอบจาก Mark Brackett สำหรับคำตอบที่ต้องการซึ่ง upvoted I (และอีก 231 คน) วิธีการที่ให้ไว้ในคำตอบของเขาช่วยให้ 1) สำหรับการใช้งานตัวแปรที่มีผลผูกพันและ 2) สำหรับเพรดิเคตที่สามารถระบุได้
คำตอบที่เลือก
สิ่งที่ฉันต้องการพูดถึงคือคำตอบของโจเอลสโปลกี้คำตอบ "เลือก" เป็นคำตอบที่ถูกต้อง
วิธีการของ Joel Spolsky นั้นฉลาด และมันก็ใช้งานได้อย่างสมเหตุสมผลมันจะแสดงพฤติกรรมที่สามารถคาดการณ์ได้และประสิทธิภาพที่คาดการณ์ได้ซึ่งให้ค่า "ปกติ" และกรณีขอบเชิงบรรทัดฐานเช่น NULL และสตริงว่าง และอาจเพียงพอสำหรับแอปพลิเคชันเฉพาะ
แต่ในแง่ทั่วไปวิธีการนี้ให้พิจารณากรณีมุมที่คลุมเครือมากขึ้นเช่นเมื่อName
คอลัมน์มีอักขระไวด์การ์ด (ที่รู้จักโดย LIKE predicate) อักขระไวด์การ์ดที่ฉันเห็นบ่อยที่สุดคือ%
(เครื่องหมายเปอร์เซ็นต์) ดังนั้นเรามาจัดการกับสิ่งนี้ที่นี่ตอนนี้และต่อไปยังกรณีอื่น ๆ
ปัญหาบางอย่างกับตัวอักษร%
'pe%ter'
พิจารณาค่าชื่อของ (สำหรับตัวอย่างที่นี่ฉันใช้ค่าสตริงตัวอักษรแทนชื่อคอลัมน์) แถวที่มีค่าชื่อ '`pe% ter' จะถูกส่งกลับโดยแบบสอบถามของฟอร์ม:
select ...
where '|peanut|butter|' like '%|' + 'pe%ter' + '|%'
แต่แถวเดียวกันนั้นจะไม่ถูกส่งคืนหากลำดับของคำค้นหาถูกย้อนกลับ:
select ...
where '|butter|peanut|' like '%|' + 'pe%ter' + '|%'
พฤติกรรมที่เราสังเกตเห็นนั้นแปลกมาก การเปลี่ยนลำดับของคำค้นหาในรายการจะเปลี่ยนชุดผลลัพธ์
เกือบจะเป็นไปโดยไม่บอกว่าเราอาจไม่ต้องการpe%ter
จับคู่เนยถั่วไม่ว่าเขาจะชอบมากแค่ไหนก็ตาม
กรณีมุมปิดบัง
(ใช่ฉันจะยอมรับว่านี่เป็นกรณีที่คลุมเครือน่าจะเป็นกรณีที่ไม่น่าจะถูกทดสอบเราจะไม่คาดหวังว่าตัวแทนในคอลัมน์ค่าเราอาจคิดว่าแอปพลิเคชันป้องกันค่าดังกล่าวจากการถูกเก็บไว้ แต่ จากประสบการณ์ของฉันฉันไม่ค่อยเห็นข้อ จำกัด ของฐานข้อมูลที่ไม่อนุญาตเฉพาะอักขระหรือรูปแบบที่จะพิจารณาว่าเป็นอักขระตัวแทนทางด้านขวาของตัวLIKE
ดำเนินการเปรียบเทียบ
การปะรู
วิธีการหนึ่งในการปะแก้หลุมนี้คือการหลบหนี%
อักขระตัวแทน (สำหรับคนที่ไม่คุ้นเคยกับประโยคหนีกับผู้ประกอบการที่นี่เป็นเชื่อมโยงไปยังเอกสาร SQL Server
select ...
where '|peanut|butter|'
like '%|' + 'pe\%ter' + '|%' escape '\'
ตอนนี้เราสามารถจับคู่% ตัวอักษร แน่นอนว่าเมื่อเรามีชื่อคอลัมน์เราจะต้องหลีกเลี่ยงสัญลักษณ์แทน เราสามารถใช้REPLACE
ฟังก์ชันเพื่อค้นหา%
อักขระและแทรกอักขระเครื่องหมายทับขวาหน้าอักขระแต่ละตัวดังนี้
select ...
where '|pe%ter|'
like '%|' + REPLACE( 'pe%ter' ,'%','\%') + '|%' escape '\'
เพื่อแก้ปัญหาด้วย% wildcard เกือบจะ
หลบหนีการหลบหนี
เราตระหนักดีว่าการแก้ปัญหาของเราได้แนะนำปัญหาอื่น ตัวละครหนี เราเห็นว่าเราจะต้องหลบหนีจากการหลบหนีของตัวละครด้วย คราวนี้เราใช้! เป็นตัวละครหนี:
select ...
where '|pe%t!r|'
like '%|' + REPLACE(REPLACE( 'pe%t!r' ,'!','!!'),'%','!%') + '|%' escape '!'
ขีดล่างด้วย
ตอนนี้เรากำลังอยู่ในระหว่างการหมุนเราสามารถเพิ่มREPLACE
หมายเลขอ้างอิงอื่นที่เป็นเครื่องหมายขีดล่าง และเพื่อความสนุกในครั้งนี้เราจะใช้ $ เป็นตัวละครในการหลบหนี
select ...
where '|p_%t!r|'
like '%|' + REPLACE(REPLACE(REPLACE( 'p_%t!r' ,'$','$$'),'%','$%'),'_','$_') + '|%' escape '$'
ฉันชอบวิธีนี้ในการหลบหนีเพราะมันทำงานใน Oracle และ MySQL รวมถึง SQL Server (ฉันมักจะใช้ \ backslash เป็นตัวละครหนีเนื่องจากเป็นตัวละครที่เราใช้ในการแสดงออกปกติ แต่ทำไมต้องถูก จำกัด ด้วยการประชุม!
วงเล็บที่น่ารำคาญ
SQL Server []
ยังช่วยให้อักขระตัวแทนที่จะถือว่าเป็นตัวอักษรโดยแนบไว้ในวงเล็บ ดังนั้นเรายังไม่ได้ทำการแก้ไขอย่างน้อยสำหรับ SQL Server เนื่องจากคู่ของวงเล็บมีความหมายพิเศษเราจะต้องหลบหนีเช่นกัน หากเราจัดการเพื่อหลบหนีวงเล็บอย่างถูกต้องอย่างน้อยที่สุดเราก็ไม่ต้องกังวลกับเครื่องหมายยัติภังค์-
และกะรัต^
ภายในวงเล็บ และเราสามารถปล่อยให้สิ่งใด%
และ_
ตัวละครในวงเล็บหนีเพราะเราจะปิดการใช้งานความหมายพิเศษของวงเล็บ
การหาคู่ของวงเล็บที่ตรงกันไม่น่าจะยาก มันยากกว่านิดหน่อยที่จะจัดการกับการเกิดขึ้นของซิงเกิล% และ _ (โปรดทราบว่ามันไม่เพียงพอที่จะหลบหนีการเกิดขึ้นของวงเล็บทั้งหมดเนื่องจากวงเล็บแบบซิงเกิลถือว่าเป็นตัวอักษรและไม่จำเป็นต้องหลบหนีตรรกะจะได้รับ fuzzier เล็กน้อยกว่าที่ฉันสามารถจัดการได้โดยไม่ต้องใช้กรณีทดสอบเพิ่มเติม .)
การแสดงออกแบบอินไลน์ยุ่งเหยิง
นิพจน์แบบอินไลน์ใน SQL นั้นยาวขึ้นและน่าเกลียดขึ้น เราอาจทำให้มันใช้งานได้ แต่สวรรค์ช่วยวิญญาณที่ยากจนที่อยู่ข้างหลังและต้องถอดรหัสมัน ในฐานะที่เป็นแฟนของฉันสำหรับการแสดงออกแบบอินไลน์ฉันมีแนวโน้มที่จะไม่ใช้ที่นี่ส่วนใหญ่เป็นเพราะฉันไม่ต้องการที่จะแสดงความคิดเห็นอธิบายเหตุผลของระเบียบและขอโทษสำหรับมัน
ฟังก์ชั่นอยู่ที่ไหน
เอาล่ะดังนั้นหากเราไม่จัดการกับสิ่งนั้นในรูปแบบอินไลน์ใน SQL ทางเลือกที่ใกล้เคียงที่สุดที่เรามีคือฟังก์ชั่นที่ผู้ใช้กำหนด และเรารู้ว่าจะไม่เร่งความเร็วสิ่งใด ๆ (เว้นแต่ว่าเราจะสามารถกำหนดดัชนีบนมันอย่างที่เราสามารถทำได้กับ Oracle) หากเราต้องสร้างฟังก์ชั่นเราควรทำอย่างนั้นในรหัสที่เรียก SQL คำให้การ.
และฟังก์ชั่นนั้นอาจมีความแตกต่างในพฤติกรรมขึ้นอยู่กับ DBMS และเวอร์ชั่น (ตะโกนออกมาให้กับนักพัฒนา Java ทั้งหมดที่คุณมีความสามารถในการใช้โปรแกรมฐานข้อมูลใด ๆ แทนกันได้)
ความรู้เกี่ยวกับโดเมน
เราอาจมีความรู้เฉพาะเกี่ยวกับโดเมนสำหรับคอลัมน์ (นั่นคือชุดของค่าอนุญาตที่บังคับใช้สำหรับคอลัมน์เราอาจรู้เบื้องต้นว่าค่าที่เก็บไว้ในคอลัมน์จะไม่มีเครื่องหมายเปอร์เซ็นต์เครื่องหมายขีดล่างหรือเครื่องหมายวงเล็บ คู่ในกรณีนั้นเราเพียงแค่ใส่ความคิดเห็นด่วนที่ครอบคลุมกรณีเหล่านั้น
ค่าที่เก็บไว้ในคอลัมน์อาจอนุญาตให้ใช้สำหรับ% หรือ _ ตัวอักษร แต่ข้อ จำกัด อาจต้องการค่าเหล่านั้นที่จะหลบหนีบางทีอาจใช้ตัวละครที่กำหนดไว้เช่นค่าที่เปรียบเทียบ LIKE "ปลอดภัย" อีกครั้งความคิดเห็นอย่างรวดเร็วเกี่ยวกับชุดของค่าที่อนุญาตและโดยเฉพาะอย่างยิ่งตัวละครที่จะใช้เป็นตัวละครหนีและไปกับวิธีการ Joel Spolsky
แต่หากขาดความรู้เฉพาะทางและการรับประกันเป็นสิ่งสำคัญที่เราจะต้องพิจารณาการจัดการกรณีมุมที่คลุมเครือและพิจารณาว่าพฤติกรรมนั้นมีเหตุผลและ "ตามข้อกำหนด"
ปัญหาอื่น ๆ ที่ recapitulated
ฉันเชื่อว่าคนอื่น ๆ ได้ชี้ให้เห็นอย่างเพียงพอแล้วในเรื่องอื่น ๆ ที่เป็นข้อกังวล:
การฉีด SQL (ทำในสิ่งที่ดูเหมือนว่าจะเป็นข้อมูลที่ผู้ใช้ระบุและรวมถึงในข้อความ SQL แทนที่จะให้พวกเขาผ่านตัวแปรการผูกการใช้ตัวแปรการผูกไม่จำเป็นต้องเป็นวิธีหนึ่งที่สะดวกในการขัดขวางการฉีด SQL วิธีจัดการกับมัน:
แผนเครื่องมือเพิ่มประสิทธิภาพโดยใช้การสแกนดัชนีแทนที่จะค้นหาดัชนีความต้องการที่เป็นไปได้สำหรับการแสดงออกหรือฟังก์ชั่นสำหรับการหลบหนีสัญลักษณ์ (ดัชนีที่เป็นไปได้ในการแสดงออกหรือฟังก์ชั่น)
การใช้ค่าตามตัวอักษรแทนตัวแปรการเชื่อมโยงส่งผลกระทบต่อความยืดหยุ่น
ข้อสรุป
ฉันชอบแนวทางของ Joel Spolsky มันฉลาด และมันใช้งานได้
แต่ทันทีที่ฉันเห็นมันฉันก็เห็นปัญหาที่อาจเกิดขึ้นทันทีและมันก็ไม่ใช่ธรรมชาติของฉันที่จะปล่อยให้มันลื่นไหล ฉันไม่ได้ตั้งใจจะวิจารณ์ความพยายามของคนอื่น ฉันรู้ว่านักพัฒนาซอฟต์แวร์หลายคนใช้งานของพวกเขาเป็นการส่วนตัวเพราะพวกเขาลงทุนไปมากและพวกเขาก็ใส่ใจกับมันมาก ดังนั้นโปรดเข้าใจว่านี่ไม่ใช่การโจมตีส่วนตัว สิ่งที่ฉันระบุที่นี่คือประเภทของปัญหาที่เกิดขึ้นในการผลิตมากกว่าการทดสอบ
ใช่ฉันไปไกลจากคำถามเดิมแล้ว แต่จะมีที่ไหนอีกที่จะออกจากบันทึกนี้เกี่ยวกับสิ่งที่ฉันคิดว่าเป็นปัญหาสำคัญกับคำตอบ "เลือก" สำหรับคำถาม?