top of page

MSSQL Öğreniyorum Serisi 01: Kütüphane Veritabanını Oluşturmak

Yazarın fotoğrafı: SEVDANUR GENC
SEVDANUR GENC
1 saat önce
6 dakikada okunur

Bu seriyle Microsoft SQL Server (MSSQL) üzerinde adım adım ilerleyeceğiz. Her yazıda aynı veritabanını kullanacağız: küçük bir okul kütüphanesi. İlk yazıda veritabanını sıfırdan kuruyoruz; tabloları oluşturuyor, kısıtları tanımlıyor ve örnek verileri ekliyoruz.


Serideki tüm SQL dosyaları GitHub'da. Kodları kopyalamak yerine indirip doğrudan SSMS'te açabilirsiniz.




Senaryo

Okul kütüphanesi kitaplarını, yazarlarını, kategorilerini ve üyelerini kayıt altına almak istiyor:


  • Bir kitabın birden fazla yazarı olabilir, bir yazarın da birden fazla kitabı olabilir.

  • Her kitap tek bir kategoriye aittir.

  • Üyeler kitap ödünç alır ve belirli bir süre içinde iade eder.


Bu cümlelerden altı tablo çıkıyor: Kategoriler, Yazarlar, Kitaplar, KitapYazar, Uyeler ve Oduncler.



ER Diyagramı


Kütüphane veritabanının ER diyagramı
Kütüphane ER diyagramı: 6 varlık, 4 ilişki

İlişki

Tür

Tabloda nasıl kurulur

Bir kategoride birden çok kitap bulunur

1:N

Kitaplar.KategoriID → Kategoriler

Bir kitabın birden çok yazarı, bir yazarın birden çok kitabı olabilir

N:M

KitapYazar ara tablosu, bileşik PK (KitapID, YazarID)

Bir üye birden çok kez ödünç alır

1:N

Oduncler.UyeID → Uyeler

Bir kitap birden çok kez ödünç verilir

1:N

Oduncler.KitapID → Kitaplar


Kural: 1:N ilişkide yabancı anahtar her zaman "N" (çok) tarafındaki tabloya eklenir. N:M ilişki doğrudan kurulamaz; iki tarafın birincil anahtarlarını taşıyan bir ara tablo gerekir.


Adım 1: Veritabanını Oluşturmak

CREATE DATABASE KutuphaneDB;
GO
USE KutuphaneDB;
GO


Adım 2: Tabloları Oluşturmak

Tablo oluşturma sırası önemlidir. Önce başka bir tabloya bağlı olmayan tabloları (Kategoriler, Yazarlar, Uyeler), sonra yabancı anahtar içeren tabloları (Kitaplar, KitapYazar, Oduncler) oluştururuz. Ters sırada çalıştırırsak FOREIGN KEY, henüz var olmayan bir tabloyu gösteremez ve hata alırız.



Bağımsız tablolar

CREATE TABLE Kategoriler (
    KategoriID   INT IDENTITY(1,1) PRIMARY KEY,
    KategoriAdi  NVARCHAR(50) NOT NULL UNIQUE
);

CREATE TABLE Yazarlar (
    YazarID  INT IDENTITY(1,1) PRIMARY KEY,
    Ad       NVARCHAR(50) NOT NULL,
    Soyad    NVARCHAR(50) NOT NULL,
    Ulke     NVARCHAR(50) NULL
);

CREATE TABLE Uyeler (
    UyeID        INT IDENTITY(1,1) PRIMARY KEY,
    Ad           NVARCHAR(50)  NOT NULL,
    Soyad        NVARCHAR(50)  NOT NULL,
    Eposta       NVARCHAR(100) NULL UNIQUE,
    Telefon      VARCHAR(15)   NULL,
    KayitTarihi  DATE NOT NULL DEFAULT GETDATE()
);
GO


Yabancı anahtar içeren tablolar

CREATE TABLE Kitaplar (
    KitapID      INT IDENTITY(1,1) PRIMARY KEY,
    ISBN         CHAR(13)      NOT NULL UNIQUE,
    KitapAdi     NVARCHAR(150) NOT NULL,
    YayinYili    SMALLINT      NULL,
    SayfaSayisi  INT           NULL CHECK (SayfaSayisi > 0),
    StokAdedi    INT           NOT NULL DEFAULT 1 CHECK (StokAdedi >= 0),
    KategoriID   INT           NOT NULL,
    CONSTRAINT FK_Kitaplar_Kategoriler
        FOREIGN KEY (KategoriID) REFERENCES Kategoriler(KategoriID)
);

-- Kitaplar - Yazarlar arasındaki N:M ilişkiyi çözen ara tablo
CREATE TABLE KitapYazar (
    KitapID  INT NOT NULL,
    YazarID  INT NOT NULL,
    CONSTRAINT PK_KitapYazar PRIMARY KEY (KitapID, YazarID),   -- bileşik birincil anahtar
    CONSTRAINT FK_KitapYazar_Kitaplar FOREIGN KEY (KitapID) REFERENCES Kitaplar(KitapID),
    CONSTRAINT FK_KitapYazar_Yazarlar FOREIGN KEY (YazarID) REFERENCES Yazarlar(YazarID)
);

CREATE TABLE Oduncler (
    OduncID          INT IDENTITY(1,1) PRIMARY KEY,
    KitapID          INT  NOT NULL,
    UyeID            INT  NOT NULL,
    OduncTarihi      DATE NOT NULL DEFAULT GETDATE(),
    SonTeslimTarihi  DATE NOT NULL,
    IadeTarihi       DATE NULL,          -- NULL ise kitap henüz iade edilmemiştir
    CONSTRAINT FK_Oduncler_Kitaplar FOREIGN KEY (KitapID) REFERENCES Kitaplar(KitapID),
    CONSTRAINT FK_Oduncler_Uyeler   FOREIGN KEY (UyeID)   REFERENCES Uyeler(UyeID),
    CONSTRAINT CK_Oduncler_Tarih    CHECK (SonTeslimTarihi >= OduncTarihi)
);
GO


Kullandığımız kısıtlar

Kısıt

Ne yapar

Örnek

PRIMARY KEY

Her satırı benzersiz tanımlar

KitapID

FOREIGN KEY

Başka tablodaki bir kayda bağlar

Kitaplar.KategoriID

UNIQUE

Aynı değerin iki kez girilmesini engeller

ISBN, Eposta

NOT NULL

Alanın boş bırakılmasını engeller

KitapAdi

DEFAULT

Değer verilmezse varsayılanı yazar

KayitTarihi = bugün

CHECK

Kurala uymayan değeri engeller

StokAdedi >= 0


Türkçe karakterlerin (ç, ğ, ı, ö, ş, ü) doğru saklanması için metin alanlarında NVARCHAR, metin değerlerinde de N'...' önekini kullanıyoruz. Tablo ve sütun adlarında ise Türkçe karakter kullanmıyoruz.



Adım 3: Veri Eklemek (INSERT)

Serinin sonraki yazılarındaki bütün örnekler bu veriye göre hazırlandı. Kayıtların her seferinde aynı numaraları alması için ID'leri SET IDENTITY_INSERT ... ON ile elle veriyoruz. Normalde IDENTITY alanlarına değer girilmez; numarayı SQL Server kendisi verir.



Kategoriler ve yazarlar

SET IDENTITY_INSERT Kategoriler ON;
INSERT INTO Kategoriler (KategoriID, KategoriAdi) VALUES
(1, N'Roman'), (2, N'Bilim'), (3, N'Tarih'), (4, N'Şiir'), (5, N'Çocuk'),
(6, N'Felsefe'), (7, N'Psikoloji'), (8, N'Biyografi'), (9, N'Bilim Kurgu'), (10, N'Polisiye');
SET IDENTITY_INSERT Kategoriler OFF;
GO

SET IDENTITY_INSERT Yazarlar ON;
INSERT INTO Yazarlar (YazarID, Ad, Soyad, Ulke) VALUES
(1,  N'Sabahattin',  N'Ali',              N'Türkiye'),
(2,  N'Yaşar',       N'Kemal',            N'Türkiye'),
(3,  N'Orhan',       N'Pamuk',            N'Türkiye'),
(4,  N'Stephen',     N'Hawking',          N'İngiltere'),
(5,  N'Leonard',     N'Mlodinow',         N'ABD'),
(6,  N'İlber',       N'Ortaylı',          N'Türkiye'),
(7,  N'Nazım',       N'Hikmet',           N'Türkiye'),
(8,  N'Antoine',     N'de Saint-Exupéry', N'Fransa'),
(9,  N'Fyodor',      N'Dostoyevski',      N'Rusya'),
(10, N'George',      N'Orwell',           N'İngiltere'),
(11, N'Agatha',      N'Christie',         N'İngiltere'),
(12, N'Isaac',       N'Asimov',           N'ABD'),
(13, N'Ahmet Hamdi', N'Tanpınar',         N'Türkiye'),
(14, N'Platon',      N'',                 N'Yunanistan'),
(15, N'Carl',        N'Sagan',            N'ABD');
SET IDENTITY_INSERT Yazarlar OFF;
GO


Kitaplar ve kitap-yazar eşleştirmesi

SET IDENTITY_INSERT Kitaplar ON;
INSERT INTO Kitaplar (KitapID, ISBN, KitapAdi, YayinYili, SayfaSayisi, StokAdedi, KategoriID) VALUES
(1,  '9780000000011', N'Kürk Mantolu Madonna',            1943, 160, 3, 1),
(2,  '9780000000028', N'İnce Memed',                      1955, 436, 2, 1),
(3,  '9780000000035', N'Kırmızı Saçlı Kadın',             2016, 204, 1, 1),
(4,  '9780000000042', N'Zamanın Kısa Tarihi',             1988, 256, 2, 2),
(5,  '9780000000059', N'Zamanın Daha Kısa Tarihi',        2005, 176, 1, 2),
(6,  '9780000000066', N'Osmanlı''yı Yeniden Keşfetmek',   2006, 296, 2, 3),
(7,  '9780000000073', N'Memleketimden İnsan Manzaraları', 1966, 480, 1, 4),
(8,  '9780000000080', N'Küçük Prens',                     1943, 112, 4, 5),
(9,  '9780000000097', N'Benim Adım Kırmızı',              1998, 472, 2, 1),
(10, '9780000000103', N'Suç ve Ceza',                     1866, 687, 3, 1),
(11, '9780000000110', N'1984',                            1949, 352, 3, 9),
(12, '9780000000127', N'Hayvan Çiftliği',                 1945, 152, 2, 1),
(13, '9780000000134', N'Doğu Ekspresinde Cinayet',        1934, 256, 2, 10),
(14, '9780000000141', N'Ben, Robot',                      1950, 272, 1, 9),
(15, '9780000000158', N'Saatleri Ayarlama Enstitüsü',     1961, 382, 2, 1),
(16, '9780000000165', N'Devlet',                          NULL, 400, 1, 6),
(17, '9780000000172', N'Kozmos',                          1980, 396, 2, 2),
(18, '9780000000189', N'Huzur',                           1949, 432, 1, 1);
SET IDENTITY_INSERT Kitaplar OFF;
GO

-- Kitap 5'in iki yazarı var (N:M ilişki örneği)
INSERT INTO KitapYazar (KitapID, YazarID) VALUES
(1, 1), (2, 2), (3, 3), (4, 4), (5, 4), (5, 5), (6, 6), (7, 7), (8, 8), (9, 3),
(10, 9), (11, 10), (12, 10), (13, 11), (14, 12), (15, 13), (16, 14), (17, 15), (18, 13);
GO

Metin içinde tek tırnak geçiyorsa iki kez yazılır: N'Osmanlı''yı Yeniden Keşfetmek'. Yayın yılı bilinmeyen "Devlet" kitabı için bilerek NULL girdik; NULL değerlerin sorgularda nasıl davrandığını sonraki yazılarda göreceğiz.



Üyeler ve ödünçler

SET IDENTITY_INSERT Uyeler ON;
INSERT INTO Uyeler (UyeID, Ad, Soyad, Eposta, Telefon, KayitTarihi) VALUES
(1,  N'Ayşe',   N'Yılmaz', N'ayse.yilmaz@okul.edu.tr',  '05321112233', '2026-09-08'),
(2,  N'Mehmet', N'Demir',  N'mehmet.demir@okul.edu.tr', '05332223344', '2026-09-08'),
(3,  N'Zeynep', N'Kaya',   N'zeynep.kaya@okul.edu.tr',  NULL,          '2026-09-10'),
(4,  N'Can',    N'Öztürk', N'can.ozturk@okul.edu.tr',   '05443334455', '2026-09-15'),
(5,  N'Elif',   N'Şahin',  NULL,                        '05554445566', '2026-09-20'),
(6,  N'Burak',  N'Çelik',  N'burak.celik@okul.edu.tr',  '05065556677', '2026-10-01'),
(7,  N'Selin',  N'Arslan', N'selin.arslan@okul.edu.tr', '05376667788', '2026-09-11'),
(8,  N'Emre',   N'Koç',    N'emre.koc@okul.edu.tr',     '05427778899', '2026-09-12'),
(9,  N'Deniz',  N'Aydın',  N'deniz.aydin@okul.edu.tr',  NULL,          '2026-09-18'),
(10, N'Merve',  N'Yıldız', N'merve.yildiz@okul.edu.tr', '05318889900', '2026-09-22'),
(11, N'Oğuz',   N'Kurt',   N'oguz.kurt@okul.edu.tr',    '05459990011', '2026-09-25'),
(12, N'Ece',    N'Polat',  N'ece.polat@okul.edu.tr',    '05360001122', '2026-10-05');
SET IDENTITY_INSERT Uyeler OFF;
GO

SET IDENTITY_INSERT Oduncler ON;
INSERT INTO Oduncler (OduncID, KitapID, UyeID, OduncTarihi, SonTeslimTarihi, IadeTarihi) VALUES
(1,  1,  1,  '2026-09-10', '2026-09-24', '2026-09-22'),
(2,  8,  1,  '2026-09-25', '2026-10-09', NULL),
(3,  2,  2,  '2026-09-12', '2026-09-26', '2026-09-30'),
(4,  4,  2,  '2026-09-28', '2026-10-12', NULL),
(5,  1,  3,  '2026-09-15', '2026-09-29', NULL),
(6,  6,  3,  '2026-09-16', '2026-09-30', '2026-09-29'),
(7,  9,  4,  '2026-09-18', '2026-10-02', NULL),
(8,  5,  5,  '2026-09-21', '2026-10-05', '2026-10-03'),
(9,  1,  5,  '2026-10-01', '2026-10-15', NULL),
(10, 10, 7,  '2026-09-22', '2026-10-06', '2026-10-05'),
(11, 11, 8,  '2026-09-24', '2026-10-08', NULL),
(12, 13, 9,  '2026-09-29', '2026-10-13', NULL),
(13, 11, 10, '2026-10-02', '2026-10-16', NULL),
(14, 15, 11, '2026-10-05', '2026-10-19', NULL),
(15, 12, 7,  '2026-10-07', '2026-10-21', NULL),
(16, 17, 4,  '2026-10-08', '2026-10-22', NULL);
SET IDENTITY_INSERT Oduncler OFF;
GO

E-posta alanı UNIQUE olduğu için SQL Server bu sütunda yalnızca bir NULL değere izin verir; bu yüzden e-postası boş olan tek üye Elif. Burak ve Ece hiç ödünç almadı. Bu kayıtlar ileride LEFT JOIN örneklerinde işimize yarayacak.


Her şeyin yerinde olduğunu kontrol edelim:


SELECT N'Kategoriler' AS Tablo, COUNT(*) AS KayitSayisi FROM Kategoriler
UNION ALL SELECT N'Yazarlar',   COUNT(*) FROM Yazarlar
UNION ALL SELECT N'Kitaplar',   COUNT(*) FROM Kitaplar
UNION ALL SELECT N'KitapYazar', COUNT(*) FROM KitapYazar
UNION ALL SELECT N'Uyeler',     COUNT(*) FROM Uyeler
UNION ALL SELECT N'Oduncler',   COUNT(*) FROM Oduncler;
-- Beklenen: 10, 15, 18, 19, 12, 16


Adım 4: Veri Güncellemek (UPDATE)

-- Zeynep, Kürk Mantolu Madonna'yı bugün iade etti
UPDATE Oduncler
SET IadeTarihi = CAST(GETDATE() AS DATE)
WHERE UyeID = 3 AND KitapID = 1 AND IadeTarihi IS NULL;

-- Küçük Prens'in stoğu 2 adet artırıldı
UPDATE Kitaplar
SET StokAdedi = StokAdedi + 2
WHERE KitapAdi = N'Küçük Prens';


Adım 5: Veri Silmek (DELETE)

-- Deneme amaçlı bir üye ekleyip silelim
INSERT INTO Uyeler (Ad, Soyad, Eposta) VALUES (N'Deneme', N'Üye', N'deneme@okul.edu.tr');

DELETE FROM Uyeler
WHERE Eposta = N'deneme@okul.edu.tr';

Dikkat: UPDATE ve DELETE komutlarında WHERE unutulursa tablodaki TÜM satırlar etkilenir. Önce aynı WHERE ile bir SELECT çalıştırıp hangi satırların etkileneceğini görmek iyi bir alışkanlıktır.

Bu iki adımda verileri değiştirdik. Sonraki yazılardaki beklenen sonuçlarla aynı sonucu almak için verileri ilk haline döndürmeniz yeterli: GitHub'daki 01_Veri_Ekleme.sql dosyasını yeniden çalıştırın.



Adım 6: Kısıtları Test Etmek

Aşağıdaki komutlar bilerek hata verir. Tek tek çalıştırıp hata mesajlarını okuyun ve hangi kısıtın devreye girdiğini bulun.


-- 1) UNIQUE: aynı ISBN ile ikinci kitap                      (Msg 2627)
INSERT INTO Kitaplar (ISBN, KitapAdi, KategoriID) VALUES ('9780000000011', N'Kopya Kitap', 1);

-- 2) FOREIGN KEY: olmayan kategori                           (Msg 547)
INSERT INTO Kitaplar (ISBN, KitapAdi, KategoriID) VALUES ('9780000000999', N'Yeni Kitap', 99);

-- 3) CHECK: negatif stok                                     (Msg 547)
UPDATE Kitaplar SET StokAdedi = -1 WHERE KitapID = 1;

-- 4) FOREIGN KEY: ödünç kaydı olan üyeyi silmek               (Msg 547)
DELETE FROM Uyeler WHERE UyeID = 1;

-- 5) NOT NULL: adı olmayan yazar                             (Msg 515)
INSERT INTO Yazarlar (Soyad) VALUES (N'İsimsiz');


Sırada Ne Var?

Veritabanımız hazır. Bir sonraki yazıda WHERE ile filtrelemeyi işleyeceğiz: karşılaştırma operatörleri, tarihli BETWEEN örnekleri ve LIKE ile metin arama.




Ders Videoları

Bu konunun ders videolarını YouTube oynatma listemde bulabilirsiniz.



Yorumlar


©2026 by Sevdanur Genc

bottom of page