ฉันใช้เวลามากในการตอบคำถาม SQL ผ่านทาง SO ฉันเจอคำถามของตระกูลนี้บ่อยครั้ง:
SELECT * FROM person WHERE birthdate BETWEEN '01/01/2017' AND '01/03/2017'
SELECT * FROM person WHERE birthdate BETWEEN '2017-01-01' AND '2017-03-01'
SELECT * FROM person WHERE birthdate BETWEEN 'some string' AND 'other string'
เช่นอาศัยการแปลงโดยนัยจากสตริงถึงวันที่ (ไม่ดี) ของพารามิเตอร์ที่กำหนดหรืออาศัยฐานข้อมูลที่แปลงค่า x ล้านแถวของฐานข้อมูลเป็นสตริงและทำการเปรียบเทียบสตริง (แย่กว่า)
ฉันแสดงความคิดเห็นเป็นครั้งคราวโดยเฉพาะอย่างยิ่งถ้าเป็นผู้ใช้ตัวแทนสูงที่เขียนคำตอบสมาร์ท แต่คนที่ฉันรู้สึกว่าควรจะมีความเลอะเทอะน้อยลง / พิมพ์ด้วยชนิดข้อมูลของพวกเขาน้อยลง
ความคิดเห็นมักจะใช้แบบฟอร์มที่มันอาจจะดีกว่าถ้าพวกเขาแปลงสตริงเป็นวันที่อย่างชัดเจนโดยใช้ to_date (Oracle), str_to_date (MySQL), แปลง (SQLSERVER) หรือกลไกที่คล้ายกัน:
--oracle
SELECT * FROM person WHERE birthdate BETWEEN TO_DATE('20170101', 'YYYYMMDD') AND TO_DATE('20170301', 'YYYYMMDD')
--mysql
SELECT * FROM person WHERE birthdate BETWEEN STR_TO_DATE('20170101', '%Y%m%d') AND STR_TO_DATE('20170301', '%Y%m%d')
--SQLS, ugh; magic numbers
SELECT * FROM person WHERE birthdate BETWEEN CONVERT(datetime, '20170101', 112) AND CONVERT(datetime, '20170301', 112)
เหตุผลทางเทคนิคของฉันสำหรับการทำเช่นนั้นก็คือมันชัดเจนว่าเป็นรูปแบบของวันที่และให้แน่ใจว่าพารามิเตอร์แหล่งที่มาไม่กี่กลายเป็นประเภทข้อมูลของคอลัมน์เป้าหมาย สิ่งนี้จะป้องกันความเป็นไปได้ใด ๆ ที่ฐานข้อมูลจะได้รับการแปลงโดยปริยายที่ไม่ถูกต้อง (อาร์กิวเมนต์วันที่ 3 มกราคม / 1 มีนาคมของตัวอย่างแรก) และป้องกันการตัดสินใจที่จะแปลงค่าวันที่นับล้านในตารางเป็นสตริง การจัดรูปแบบที่อาจไม่ตรงกับรูปแบบของวันที่ในพารามิเตอร์สตริงภายใน sql) เพื่อทำการเปรียบเทียบ - horrors abound
เหตุผลทางสังคม / วิชาการของฉันสำหรับการทำเช่นนั้นคือ SO เป็นเว็บไซต์การเรียนรู้ ผู้คนที่อยู่ในนั้นจะได้รับความรู้ไม่ว่าโดยนัยหรือโดยชัดแจ้ง ในการเข้าสู่มือใหม่ด้วยคำค้นหานี้เป็นคำตอบ:
SELECT * FROM person WHERE birthdate BETWEEN '2017-01-01' AND '2017-03-01'
อาจทำให้พวกเขาคิดว่าสิ่งนี้มีเหตุผลปรับวันที่สำหรับรูปแบบที่ต้องการ:
SELECT * FROM person WHERE birthdate BETWEEN '01/01/2017' AND '01/03/2017'
หากอย่างน้อยพวกเขาเห็นความพยายามที่ชัดเจนในการแปลงวันที่พวกเขาอาจเริ่มทำมันสำหรับรูปแบบวันที่แปลก ๆ ของพวกเขาและฆ่าแมลงตลอดกาลบางอย่างก่อนที่จะเกิดขึ้น ท้ายที่สุดเรา (I) ลองและห้ามไม่ให้ผู้คนเข้าสู่พฤติกรรมการฉีด SQL (และใครก็ตามที่สนับสนุนการตั้งค่าการสืบค้นแล้วประกาศให้คนขับรถที่@pBirthdate
เป็นสตริงเมื่อส่วนหน้ามีประเภทวันที่และเวลา?
กลับไปที่สิ่งที่เกิดขึ้นหลังจากที่ฉันแนะนำ: ฉันมักจะได้รับ pushback บางอย่างเพื่อ "ชัดเจน, ใช้ x" คำแนะนำเช่น "คนอื่นทำมัน", "มันใช้ได้สำหรับฉันเสมอ", "แสดงคู่มือหรือเอกสารอ้างอิงให้ฉัน ที่บอกว่าฉันควรจะชัดเจน "หรือ" อะไร "
ฉันถามว่าในการตอบสนองต่อสิ่งเหล่านี้ไม่ว่าพวกเขาจะค้นหาคอลัมน์ int หรือไม่โดยการWHERE age = '99'
ผ่านอายุเป็นสตริง "ไม่ต้องงี่เง่าเราไม่จำเป็นต้องใส่" เมื่อค้นหา int "เป็นการตอบสนองดังนั้นจึงมีความซาบซึ้งใจต่อประเภทข้อมูลที่แตกต่างกันในใจบางแห่ง แต่บางทีก็อาจจะไม่เกี่ยวข้องกับโลจิคัลกระโดดที่ค้นหา int คอลัมน์โดยการส่งผ่านสตริง (เห็นได้ชัดว่าโง่) และการค้นหาคอลัมน์วันที่โดยการส่งผ่านสตริง
ดังนั้นใน SQLs ของเราเรามีวิธีเขียนสิ่งต่าง ๆ เป็นตัวเลข (ใช้ตัวเลขโดยไม่มีตัวคั่น) สิ่งต่าง ๆ เป็นสตริงสตริง (ใช้อะไรก็ได้ระหว่างตัวคั่นเครื่องหมายวรรคตอน) .. ทำไมไม่มีตัวคั่นสำหรับวันที่ มันเป็นประเภทข้อมูลพื้นฐานในฐานข้อมูลส่วนใหญ่หรือไม่ สิ่งทั้งหมดนี้อาจจะแก้ไขได้เพียงแค่มีวิธีการเขียนวันที่ในลักษณะเดียวกับจาวาสคริปต์ที่ให้เราระบุ regex โดยการใส่/
ด้านข้างของอักขระบางตัว /Hello\s+world/
. ทำไมไม่มีอะไรเป็นเดท
ตามความรู้ของฉัน (เฉพาะ) Microsoft Access มีสัญลักษณ์ที่ระบุว่า "วันที่เขียนระหว่างตัวคั่นเหล่านี้" เพื่อให้เราได้รับทางลัดที่ดีเช่นWHERE datecolumn = #somedate#
แต่การนำเสนอวันที่ยังคงมีปัญหาเช่น mm / di vs dd / mm เนื่องจาก MS เล่นอย่างรวดเร็วและหลวมกับสิ่งที่ฝูงชน VB คิดว่าเป็นความคิดที่ดี
กลับไปที่ประเด็นหลัก: ฉันเถียงว่ามันเป็นการฉลาดที่จะมีความชัดเจนกับสื่อนี้ที่บังคับให้เราผ่านประเภทข้อมูลที่หลากหลายเป็นสตริง ..
มันเป็นการยืนยันที่ถูกต้อง?
ฉันควรทำสงครามครูเสดต่อไปไหม? เป็นจุดที่ถูกต้องหรือไม่ที่การพิมพ์อย่างเข้มงวดเป็นโมเดิร์นไม่เลย? หรือ RDBMS ทุกอัน (รวมถึงเวอร์ชั่นโบราณ) จะออกมาที่นั่นหรือไม่เมื่อมีการผลักข้อความค้นหาให้WHERE datecolumn = 'string value'
แปลงสตริงเป็นวันที่อย่างถูกต้องและทำการค้นหาโดยไม่ต้องแปลงข้อมูลตาราง / สูญเสียการใช้ดัชนี? ฉันสงสัยว่าอย่างน้อยที่สุดก็จากประสบการณ์ส่วนตัวของ Oracle 9 ฉันสงสัยว่าอาจมีบางสถานการณ์ที่ต้องออกไปหากมีการเขียนสตริงในรูปแบบมาตรฐาน ISO อยู่เสมอและคอลัมน์ก็เป็นบางวันที่แล้ว พารามิเตอร์สตริงจะถูกแปลงโดยปริยายอย่างถูกต้องเสมอ สิ่งนี้ทำให้ถูกต้องหรือไม่
มันเป็นงานที่คุ้มค่าหรือไม่?
หลายคนดูเหมือนจะไม่ได้รับมันหรือไม่สนใจหรือแสดงความเจ้าเล่ห์ในการที่ ints ของพวกเขาเป็น ints แต่วันที่ของพวกเขาเป็นสตริง .. ร่วมกันมากที่สุดแม้ว่าจะเป็นที่ไม่กี่คนที่เคยหันกลับมาและกล่าวว่า "คุณรู้ อะไรฉันเห็นด้วยกับจุดของคุณฉันจะชัดเจนเกี่ยวกับวันที่ของฉันจากนี้ไป "
WHERE age = '0x0F'
เป็นวิธีที่ถูกต้องในการหวังว่าฐานข้อมูลจะค้นหาเด็กอายุสิบห้าปีหรือไม่
WHERE datecolumn =
01/02 / 12'` ที่เป็นไปได้ที่พวกเขาจะขอปี 1912, 2012, 2001, 1901, 12 หรือ 1 นอกจากนี้ยังมีปัญหานอกโลกฐานข้อมูลจำนวน ของโปรแกรมเมอร์ที่ไม่สามารถเข้าใจว่าทำไมการแปลง"09"
เป็น int ที่เป็นสาเหตุของความผิดพลาดเป็นพยุหะ9 ไม่ได้เป็นฐานแปดหลักที่ถูกต้องและเป็นผู้นำ 0 ทำให้ฐานแปดสตริงในจำนวนมากของระบบ