SO üzerinde SQL soruları cevaplamak için çok zaman harcamak. Ben sık sık bu ilk sorguları rastlamak:
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'
yani ya dizeden tarihe örtük bir dönüşüme (kötü), verilen parametrelere dayanarak ya da x milyon veritabanı satırı değerlerini dizeye dönüştüren ve bir dize karşılaştırması (daha kötü) yaparak veritabanına güvenerek
Bazen akıllı bir cevap yazan, ancak gerçekten veri türleriyle daha az özensiz / dize yazılmış olması gerektiğini hissettiğim yüksek rep kullanıcısıysa, bir yorum yaparım
Yorum genellikle to_date (Oracle), str_to_date (MySQL), convert (SQLSERVER) veya benzer bir mekanizma kullanarak dizelerini açıkça tarihlere dönüştürürlerse muhtemelen daha iyi olacağı biçimini alır:
--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)
Bunu yapmak için teknik gerekçelerim, tarihin biçimine göre açık olması ve birkaç kaynak parametresinin kesinlikle hedef sütunun veri türü olmasını sağlar. Bu, veritabanının örtük bir dönüştürme hatası alma olasılığını önler (ilk örneğin 3 Ocak / 1 Mart bağımsız değişkeni) ve db'nin tablodaki bir milyon tarih değerini dizeye dönüştürmeye karar vermesini önler (sunucuya özel bir tarih kullanarak) sql içindeki dize parametrelerindeki tarih biçimiyle bile eşleşmeyebilecek biçimlendirme)
Benim sosyal / akademik gerekçem SO'nun bir öğrenme sitesi olması; üzerindeki insanlar bilgiyi dolaylı ya da açıkça edinirler. Bir cevap olarak bu sorguyu içeren bir acemi vurmak için:
SELECT * FROM person WHERE birthdate BETWEEN '2017-01-01' AND '2017-03-01'
Tercih ettikleri bazı formatlar için tarihi ayarlayarak, bu durumun mantıklı olduğunu düşünmelerine neden olabilir:
SELECT * FROM person WHERE birthdate BETWEEN '01/01/2017' AND '01/03/2017'
En azından tarihi dönüştürmek için açık bir girişimde bulunduysa, tuhaf tarih formatları için yapmaya başlayabilir ve ortaya çıkmadan önce sonsuza kadar bazı böcekleri öldürebilirler. Sonuçta, (I) insanları SQL enjeksiyon alışkanlığına girmekten caydırmaya çalışıyoruz (ve herkes bir sorguyu parametreleştirmeyi ve sonra @pBirthdate
ön uç datetime türüne sahip olduğunda, bir dize olan sürücüyü bildirmeyi savunur mu?)
Tavsiyemi yaptıktan sonra ne olduğuna geri dönelim: "Herkes açıkça", "her zaman benim için çalışıyor", "bana bazı manuel veya referans dokümanları göster" gibi "açık, x kullan" önerisine bir itiraz alıyorum açık "veya hatta" ne ?? "
Bunlardan bazılarına yanıt olarak WHERE age = '99'
, çağa bir dize olarak geçerek int sütununda arama yapıp yapmadıklarını sordum . "Aptal olma, 'int'i ararken' koymamız gerekmez" yanıtı gelir, bu yüzden akıllarında bir yerde farklı veri türleri için bazı takdirler vardır, ancak belki de int'i araştıran mantıksal sıçrayışla bağlantı yoktur Bir dizeyi geçirerek (görünüşte aptalca) ve bir dizeyi geçirerek (görünüşte mantıklı) bir tarih sütununda arama yapmak ikiyüzlülüktür
SQL'lerimizde bir şeyleri sayılar (sınırlayıcılar olmadan sayısal kullanın), dize dizeleri (kesme işareti sınırlayıcıları arasında herhangi bir şey kullanın) olarak yazmanın bir yolu var. Neden tarihler için sınırlayıcı yok? Çoğu DB'de böyle temel bir veri türü? Bütün bunlar, aynı şekilde bir tarih yazmanın bir yoluna sahip olarak çözülebilir mi? Javascript /
, bazı karakterlerin her iki tarafını da koyarak bir normal ifadeyi belirlememize izin verir . /Hello\s+world/
. Tarihler için neden bir şey yok?
Aslında, bildiğim kadarıyla, Microsoft Access aslında "bu sınırlayıcılar arasında bir tarih yazılmıştır" şeklinde sembollere sahiptir, bu yüzden iyi bir kısayol alabiliriz, WHERE datecolumn = #somedate#
ancak tarih sunumu hala mm / di vs dd gibi problemler vermekle yükümlüdür. / mm, MS her zaman hızlı ve gevşek oynadığı için VB kalabalığının iyi bir fikir olduğunu düşündü
Ana noktaya geri dönelim: Bizi dizeler olarak çok sayıda farklı veri türünden geçirmeye zorlayan bu ortamla açık olmanın akıllıca olduğunu düşünüyorum.
Geçerli bir iddia mı?
Haçlı seferine devam etmeli miyim? Dize yazmanın modern bir hayır-hayır olduğu geçerli bir nokta mı? Ya da her RDBMS (eski sürümler dahil), bir sorgu WHERE datecolumn = 'string value'
kesinlikle kesinlikle dizeyi bir tarihe dönüştürmek ve tablo verilerini dönüştürmeden / dizin kullanımını kaybetmeden arama yapmak zaman orada olacak? En azından Oracle 9'un kişisel deneyiminden hayır. string parametresi her zaman doğru bir şekilde dolaylı olarak dönüştürülecektir. Bu doğru mu?
Değerli bir görev mi?
Pek çok insan bunu anlamıyor ya da umursamıyor ya da ints ints, ancak tarihleri dizgiler olduğu için iki yüzlülük sergiliyorlar. ne, senin fikrinle aynı fikirdeyim.
WHERE age = '0x0F'
bir veritabanı on beş yaşındakiler için arama umuyoruz geçerli bir yol olup olmadığını sormak için örnek uzatmayı düşündün ..
WHERE datecolumn =
01/02/12 '' ile sorun yaşadığını bile gördüm , 1912, 2012, 2001, 1901, 12 veya 1 yılını sormaları mümkün. Ayrıca veritabanı dünyasının dışında bir sorun, sayı"09"
bir int'e dönüştürmenin neden bir çökmeye neden olduğunu anlayamayan programcılar arasında lejyon, 9 geçerli bir sekizlik basamak değildir ve önde gelen 0, birçok sistemde dize sekizlik yapar