12 Aralık 2006

Tek Kolonda Tutulan Çoklu Değerler

Veritabanımızda bir verinin değeri birden fazla değerden oluşabiliyorsa (checkbox), bu durumda bu alanları saklamak için 2 yöntem kullanabiliriz. Birincisi bu değerleri bir key ilişkisiyle ayrı bir tabloda satırlar halinde tutmak, ikincisi ayırıcı bir karakter yardımıyla bu değerleri tek bir alanda tutmak. Birinci yöntemde raporlamada problem yaşanmaz, fakat ikinci yöntemde bu değerlerin gösterimi ve analizi biraz daha zor olacaktır.
Böyle bir durumla karşılaşırsak yazacağımız bir Split fonksiyonuyla işimizi kolaylaştırabiliriz.

Alan değerimizin izlenen TV kanalları olduğunu varsayalım. Değerleri de;

1: ATV
2: KANAL D
3: SHOW TV
4: NTV
5: CNN TURK


olsun. Ayırıcı işaret olarak ";" kullandığımızı varsayalım.

--Önce Split fonksiyonunu yazalım;

CREATE FUNCTION [dbo].[Split] (@Str NVARCHAR(500), @Delimiter CHAR(1))
RETURNS @Results TABLE (Rows nvarchar(4000))
AS
BEGIN
DECLARE @Indx INT
DECLARE @Prt NVARCHAR(4000)
SELECT @Indx = 1
IF @Str Is NULL RETURN
WHILE @Indx != 0
BEGIN
SELECT @Indx = CharIndex(@Delimiter, @Str)
IF @Indx != 0
SELECT @Prt = left(@Str, @Indx - 1)
ELSE
SELECT @Prt = @Str
IF (@Prt!='0' and @Prt!='') INSERT INTO @Results(Rows) VALUES (@Prt)
SELECT @Str = right(@Str, Len(@Str) - @Indx)
IF Len(@Str) = 0 BREAK
END
RETURN
END

Daha sonra test için bir kullanıcı tablosu yaratalım,
CREATE TABLE [dbo].[UserInfo](
[userid] [int] NOT NULL,
[Email] [varchar](100) COLLATE Turkish_CI_AS NOT NULL,
[channel] [varchar](100) COLLATE Turkish_CI_AS NOT NULL
)

Sonra bu tabloya test kayıtları ekleyelim

INSERT INTO [dbo].[UserInfo](userid,Email,Channel)
VALUES (887,'test1@test.com','1;0;0;4;5')
INSERT INTO [dbo].[UserInfo](userid,Email,Channel)
VALUES (965,'test2@test.com','1;0;3;0;0')

Daha sonra kanal seçim tablosunu oluşturalım
CREATE TABLE [dbo].[Channels](
[userid] [int] NOT NULL,
[Channel] [int] NOT NULL
)

Yazdığımız Split fonksiyonunu kullanarak kayıtları ekleyelim
DECLARE @channel varchar(200)
DECLARE @userid varchar(200)
DECLARE @cr_channel CURSOR
SET @cr_channel = CURSOR FOR
SELECT channel,userid FROM dbo.UserInfo
OPEN @cr_channel
FETCH NEXT FROM @cr_channel INTO @channel,@userid
WHILE ( @@FETCH_STATUS = 0)
BEGIN
INSERT INTO
Channels(userid, channel)
SELECT @userid, * From Split (@channel,';')
FETCH NEXT FROM @cr_channel INTO @channel,@userid
END

Channels tablosunda userid ve Channel olarak satır bazlı kayıtlarımız oluştu. Bu kayıtları artık çok rahat bir şekilde kullanabiliriz.

07 Aralık 2006

Delete Ve Truncate Komutları Arasındaki Fark

Bazen çözüme ulaşmak için kullanımı aynı gibi görünen farklı yöntemler kullanıyoruz. DELETE ve TRUNCATE ikilisi de bunlardan biri aslında. Peki ikisi arasında ne fark var? Aslında bu farklar bir hayli fazla.

DELETE komutunda işlem sonunda satırlar fiziksel olarak silinir ve satır bazlı olarak loglanır. Bu yüzden yüksek miktarda satıra DELETE işlemi sık periyotta uygulandığında log file zamanla büyük boyutlara ulaşacaktır. TRUNCATE komutu da loglama yapar;fakat farklı bir yolla. TRUNCATE komutu işleme tabi tutulan tablodaki kayıtları bulunduğu pagefile ları işaretler. Aslında TRUNCATE işleminde data silinmeyip daha sonra kullanılmak üzere işaretlenmektedir. Bu da TRUNCATE işleminin DELETE işlemine göre çok daha performanslı çalışmasını sağlar.

DELETE komutu Foreign Key veya diğer Constraint lere zarar vermeden kayıtları siler.
Foreign Key Constraint i olan bir tabloya TRUNCATE işlemi uygulanamaz. Önce Constraint lerin silinip, TRUNCATE işleminden sonra tekrar tanımlanması gerekecektir. Ayrıca bu işlemi yapacak olan user ın db_owner,ddl_admin veya owner haklarından birisine sahip olması gerekir.

TRUNCATE işlemi sonunsa Identity alan değerleri ilk değerlerinden tekrar başlar. Örneğin 1'den başlayan Identity değeri olan ve içerisinde 100 satır bulunan bir tablo olduğunu varsayalım. TRUNCATE işlemi sonunda boş tabloya bir satır eklediğimizde alacağı değer 1 dir, fakat DELETE işleminden sonra bu değer 101 olacaktır.