Bu blogda doğrudan yeni teknolojileri anlatmak yerine eski ve yeni teknolojileri gözetmeksizin günlük hayatta, projelerde ihtiyaç duyulan yöntemleri, ipuçlarını, konuları, örnekleri, yazılım geliştirme sürecinde dikkat edilmesi gereken konuları vermeye çalışıyoruz. Yazılım mühendisliğiyle ve C# veya VB.NET programlama dilleriyle ilgili detaylı konuları yakın zamanda çıkacak olan kitaplarımda vermeye çalıştım. Bu küçük yazıda da özellikle veri ambarı raporlama sistemlerinde işlerimizi kolaylaştıracak Tarih tablosunun içeriğini vereceğiz. “Date dimension table” olarak isimlendirilen bu tablo tüm data warehouse sistemlerinde ortak olup sistemin kullanım amacına uygun olarak farklı detaylar içerir. Belli tarih aralığının detaylarını içeren bu tablo çalışma anında tarihsel hesaplamaların neden olacağı performans ve zaman kaybını engeller. Bu tablo aynı zamanda OLTP uygulamalarında lookup olarak ta kullanılabilir.
Örnek verdiğimiz aşağıda tabloda bir tarihin, tarih formatı, hafta ve ay bilgisi, haftanın, ayın ve yılın kaçıncı günü olduğu, haftasonuna denk gelip gelmediği gibi bilgiler verilmektedir.
CREATE TABLE L_Tarih( Bugun int NOT NULL, --YYYYMMDD formatında tarih. Tablonun primary key'i. FormatliBugun char(10) NULL,--DD.MM.YYYY formatında tarih GunAd char(10) NULL, AyAd char(10) NULL, TarihAd varchar(50) NULL,--'10 Aralık 2007 Pazartesi' gibi BuYil char(4) NULL,--Sene bilgisi BuAy char(6) NULL,--Yıl ve ay bilgisi. YYYYMM BuHafta char(6) NULL,--Yıl ve hafta bilgisi. YYYYWW Dun char(10) NULL, GecenHaftaBugun char(10) NULL, GecenAyBugun char(10) NULL, GecenYil char(4) NULL, GecenYilBugun char(10) NULL, GecenYilBuHafta char(6) NULL, GecenYilBuAy char(6) NULL, HaftaIlkGun char(10) NULL,--Bugünün bulunduğu haftanın başı HaftaSonGun char(10) NULL,--Bugünün bulunduğu haftanın sonu AyIlkGun char(10) NULL, AySonGun char(10) NULL, HaftaGunNo int NULL,--Haftanın kaçıncı günü AyGunNo int NULL,--Ayın kaçıncı günü YilGunNo int,--Yılın kaçıncı günü AyGunSayi int NULL, YilIlkGun char(10) NULL, YilSonGun char(10) NULL, HaftaSonu bit NULL--Haftasonu olup olmadığını belirtir )
Şeması bu şekilde olan tabloya aşağıdaki script’i çalıştırarak iki tarih aralığındaki tarih detaylarını yazdıralım.
DECLARE @IlkTarih DATETIME
DECLARE @SonTarih DATETIME
SET @IlkTarih = '01-01-2007'
SET @SonTarih = '31-12-2008'
DECLARE @Bugun INT, @FormatliBugun CHAR(10), @GunAd CHAR(10), @AyAd CHAR(10),
@TarihAd VARCHAR(50), @BuYil CHAR(4), @BuAy CHAR(6), @BuHafta CHAR(6),
@Dun CHAR(10), @GecenHaftaBugun CHAR(10), @GecenAyBugun CHAR(10),
@GecenYil CHAR(4), @GecenYilBugun CHAR(10),@GecenYilBuHafta CHAR(6),
@GecenYilBuAy CHAR(6),@HaftaGunNo INT, @AyGunNo INT,@YilGunNo INT,
@HaftaIlkGun CHAR(10), @HaftaSonGun CHAR(10),@AyGunSayi INT,
@AyIlkGun CHAR(10), @AySonGun CHAR(10), @YilIlkGun CHAR(10),
@YilSonGun CHAR(10), @HaftaSonu BIT
WHILE @IlkTarih <= @SonTarih
BEGIN
SET @Bugun=CONVERT(VARCHAR(8), @IlkTarih, 112)
SET @FormatliBugun=CONVERT(VARCHAR(10), @IlkTarih, 104)
SET @GunAd=DATENAME(dw, @IlkTarih)
SET @AyAd=DATENAME(mm, @IlkTarih)
SET @TarihAd=CAST(DATEPART(dd, @IlkTarih) AS CHAR(2)) +' '+ DATENAME(mm, @IlkTarih) + ' '
+ CAST(DATEPART(yy, @IlkTarih) AS CHAR(4))+' '+ @GunAd
SET @BuYil=DATENAME(yy, @IlkTarih)
SET @BuAy=LEFT(@Bugun,6)
SET @BuHafta=CAST(DATEPART(ww, @IlkTarih) as CHAR(2))
--Tek hane ise başına "0" ekleyelim
SET @BuHafta=@BuYil+REPLICATE('0', 2 - LEN(@BuHafta))+@BuHafta
SET @Dun= CONVERT(VARCHAR(8),DATEADD(dd,-1, @IlkTarih),112)
SET @GecenHaftaBugun=CONVERT(VARCHAR(8),DATEADD(dd,-7, @IlkTarih),112)
SET @GecenAyBugun=CONVERT(VARCHAR(8),DATEADD(mm,-1, @IlkTarih),112)
SET @GecenYil=CONVERT(VARCHAR(8),DATEADD(yy,-1, @IlkTarih),112)
SET @GecenYilBugun=CONVERT(VARCHAR(8),DATEADD(dd,-365, @IlkTarih),112)
SET @GecenYilBuHafta=CAST(DATEPART(ww, @GecenYilBugun) as CHAR(2))
--Tek hane ise başına "0" ekleyelim
SET @GecenYilBuHafta=@GecenYil+REPLICATE('0', 2 - LEN(@GecenYilBuHafta))+@GecenYilBuHafta
SET @GecenYilBuAy=LEFT(@GecenYilBugun,6)
--Tarihin bulunduğu haftanın ilk günü
SET @HaftaIlkGun=CONVERT(VARCHAR(8),DATEADD(dd,-(DATEPART(dw, @IlkTarih) - 1),@IlkTarih),112)
--Tarihin bulunduğu haftanın son günü
SET @HaftaSonGun=CONVERT(VARCHAR(8),DATEADD(dd,-(DATEPART(dw, @IlkTarih) - 7),@IlkTarih),112)
--Ayın ilk günü
SET @AyIlkGun=@BuAy+'01'
--Ayın son günü
SET @AySonGun=CONVERT(VARCHAR(8),DATEADD(d, -DAY(DATEADD(m,1,@IlkTarih)),DATEADD(m,1,@IlkTarih)),112)
SET @YilIlkGun=@BuYil+'0101'
SET @YilSonGun=@BuYil+'0131'
--Ayın kaç gün olduğunu hesaplayalım
SET @AyGunSayi=DAY(DATEADD(d, -DAY(DATEADD(m,1,@IlkTarih)),DATEADD(m,1,@IlkTarih)))
--Tarihin haftanın kaçıncı günü olduğunu hesaplayalım
SET @HaftaGunNo=DATEPART(dw , @IlkTarih)
--Tarihin ayın kaçıncı günü olduğunu hesaplayalım
SET @AyGunNo=DATEPART(day , @IlkTarih)
--Tarihin yılın kaçıncı günü olduğunu hesaplayalım
SET @YilGunNo=DATEPART(dy , @IlkTarih)
--Tarihin haftasonu olup olmadığını bulalım
SET @HaftaSonu= CASE WHEN @HaftaGunNo IN (6,7) THEN 1 ELSE 0 END
--Elde ettiğimiz bilgileri lookup tablosuna aktaralım
INSERT L_Tarih (Bugun, FormatliBugun, GunAd, AyAd, TarihAd,
BuYil,BuAy,BuHafta,Dun,GecenHaftaBugun,GecenAyBugun,
GecenYil,GecenYilBugun,GecenYilBuHafta,GecenYilBuAy,
HaftaIlkGun,HaftaSonGun,AyIlkGun,AySonGun,HaftaGunNo,
AyGunNo,YilGunNo,AyGunSayi,YilIlkGun,YilSonGun,HaftaSonu)
VALUES(@Bugun, @FormatliBugun, @GunAd, @AyAd, @TarihAd,
@BuYil,@BuAy,@BuHafta,@Dun,@GecenHaftaBugun,@GecenAyBugun,
@GecenYil,@GecenYilBugun,@GecenYilBuHafta,@GecenYilBuAy,
@HaftaIlkGun,@HaftaSonGun,@AyIlkGun,@AySonGun,@HaftaGunNo,
@AyGunNo,@YilGunNo,@AyGunSayi,@YilIlkGun,@YilSonGun,@HaftaSonu)
--Döngü içerisinde bir sonraki güne geçelim
SET @IlkTarih = DATEADD(dd, 1, @IlkTarih)
END
Bu scriptleri dili Türkçe olan bir kullanıcıyla çalıştırdığımızda tarih tablosu Türkçe formatına göre oluşturulur. L_Tarih tablosuna 2007 ve 2008 yıllarına ait tarih bilgileri eklenmiş olur.

Bu tablo üzerinde bazı sorgular çalıştıralım. 2008 yılında hangi günden kaç adet bulunduğunu sorgulayalım.
SELECT Max(HaftaGunNo) [Gün Numarası],GunAd [Gün Adı], COUNT(*) Adet FROM L_Tarih WHERE BuYil = 2008 GROUP BY GunAd ORDER BY 1
| Gün Numarası | Gün Adı | Adet |
| 1 | Pazartesi | 52 |
| 2 | Salı | 53 |
| 3 | Çarşamba | 53 |
| 4 | Perşembe | 52 |
| 5 | Cuma | 52 |
| 6 | Cumartesi | 52 |
| 7 | Pazar | 52 |
Görüldüğü gibi 2008 yılında 53 adet Salı ve Çarşamba günü bulunmaktadır. Aynı şekilde 2008 yılında ayların kaçar güne sahip olduğunu sorgulayalım.
SELECT BuAy [Ay], Max(AyAd) [Ay Adı], COUNT(Bugun) [Gün Sayısı] FROM L_Tarih WHERE BuYil = 2008 GROUP BY BuAy ORDER BY 1
| Ay | Ay Adı | Gün Sayısı |
| 200801 | Ocak | 31 |
| 200802 | Şubat | 29 |
| 200803 | Mart | 31 |
| 200804 | Nisan | 30 |
| 200805 | Mayıs | 31 |
| 200806 | Haziran | 30 |
| 200807 | Temmuz | 31 |
| 200808 | Ağustos | 31 |
| 200809 | Eylül | 30 |
| 200810 | Ekim | 31 |
| 200811 | Kasım | 30 |
| 200812 | Aralık | 31 |
Bu tür tablolar OLAP uygulamalarında özetleme seviyeleri olarak kullanılır. Örneğin özellikle reel büyüme değerleri için haftalık, aylık, yıllık karşılaştırmalar herhangi bir tarih hesaplaması yapılmadan kolayca buradaki veriler kullanılabilir. Örneğin satış, sipatiş tablolarıyla JOIN edilerek farklı zaman dilimine göre satış veya sipariş analizleri yapılabilir.



Eylül 15th, 2009 at 22:28
SP ile cursor kullanıp tarihler arası toplu kayıt yapmaya çalışıyorum.kaydetme kısmı çalışıyor ama update kısmında sorun yaşıyorum update etmek istediğimde tarih aralığındaki tüm deperleri bitiş tarihi ile aynı yapıyor.kodlarım aşağıda acaba bakabilirmisiniz nerde hata yapıyorum.bir haftadır çatlattı beni çözemedim.
ALTER PROCEDURE diger
@bastarih datetime,
@bittarih datetime,
@otel nvarchar(50),
@kort nvarchar(50),
@zaman1 text,
@kayitno int
AS
DECLARE @tarih1 datetime
DECLARE @tarih2 datetime
DECLARE @otel1 nvarchar(50)
DECLARE @kort1 nvarchar(50)
DECLARE @zaman19 nvarchar(50)
DECLARE @kayitno1 int
DECLARE @MyCursor CURSOR
SET @MyCursor = CURSOR FOR
SELECT tarih,otel,kort,zaman1,kayitno FROM tennis
OPEN @MyCursor
FETCH NEXT FROM @MyCursor INTO @tarih1,@otel1,@kort1,@zaman19,@kayitno1
SELECT tarih,otel,kort,zaman1,kayitno FROM tennis
WHILE (@@FETCH_STATUS = 0)
BEGIN
IF EXISTS (SELECT kayitno FROM tennis WHERE kayitno=@kayitno)
begin
while @basTarih <= @bitTarih
begin
UPDATE tennis SET tarih=@bastarih,otel=@otel,kort=@kort,zaman1=@zaman1,kayitno=@kayitno
WHERE kayitno=@kayitno
set @basTarih = dateadd(day,1,@basTarih)
end
end
else
begin
while @basTarih <= @bitTarih
begin
INSERT INTO tennis(tarih,otel,kort,zaman1,kayitno)
VALUES (@bastarih,@otel,@kort,@zaman1,@kayitno)
set @basTarih = dateadd(day,1,@basTarih)
end
END
FETCH NEXT FROM @MyCursor INTO @tarih1,@otel1,@kort1,@zaman19,@kayitno1
END
SELECT tarih,otel,kort,zaman1,kayitno FROM tennis
CLOSE @MyCursor
DEALLOCATE @MyCursor
Eylül 17th, 2009 at 11:01
Yazdığın sorgu doğru çalışıyor fakat bir mantık hatası var.
UPDATE tennis SET tarih=@bastarih,otel=@otel,kort=@kort,zaman1=@zaman1,kayitno=@kayitno
WHERE kayitno=@kayitno
bu ifade tabloyu o tarih aralığı kadar güncelliyor yani her defasında tarih alanını yeni @bastarih değeriyle güncelliyor ve döngüden çıkarken doğal olarak tablo ensonki tarih ile güncellenmiş olacak. tennis tablosunda her tarih için ayrı satırları güncellemesini bekliyorsun sanırım ama WHERE kayitno=@kayitno olduğu için her defasında bu koşula uyan tüm kayıtlar güncellenmiş olacak ve yeni tarih eski tarihi ezecektir. O tabloyu başka bir anahtar kolonla güncellemek lazım veya tablodaki tüm kayıtları silip yeniden insert yapmak lazım.
Eylül 17th, 2009 at 13:27
anahtar kolon olarak rez_id kolonunu kullanıyorum dediğinizi yapınca iki tarih arası update etti yani tarih kısmında sorun çıkarmadı ama benim diğer kolonlarım olan zaman1,zaman2,zaman3,zaman4 bunlarda güncellerken ben zaman4 veri giriyorum ama bunu yaparken zaman1,zaman2 gibi diğer sütünlardaki verileri siliyor.
mesala ;
zaman1–zaman2–zaman3–zaman4
AAAAA BBBB CCCC DDDD
AAAAA VVVV DDDD ZZZZ Burda zaman4 deki (ZZZZ) değiştirip (TTTT) Yapınca aşağıdaki gibi diğer sutunları siliyor
zaman1–zaman2–zaman3–zaman4
AAAAA BBBB CCCC DDDD
? ? ? TTTT güncelleme sonrası soru işareti olan yerler böyle oluyor.neden yapabilir bunu.SP ve Cursor kullanımında acemi olduğum için çok zorlanıoyrum.
Eylül 18th, 2009 at 07:43
Unsal tam olarak ne yapmak istediğin bilmediğim ve veriler eksik olduğu için buradan yardımcı olmakta zorlanıyorum. Stored Procedure veya Cursor yapıları SQL’de çok kolay yazılır ki bunları zaten biliyorsun. Bence sorun yapmak istediklerinde mantıksal hatalar var. Onları gözden geçirmelisin. Adım adım gitmende fayda vardır.