---
title: 'Küme İşlemleri'
source: 'https://academia.sh/tr/kurslar/sql-temelleri/kume-islemleri'
course: 'SQL Temelleri'
language: tr
updated: '2026-08-17T18:09:02+00:00'
license: 'CC BY-SA 4.0'
---

# Küme İşlemleri

İki sonuç kümesini birleşim, kesişim ve fark olarak birleştirmek; yinelenen satırların korunup korunmaması, boş değerin küme işlemlerindeki eşitliği ve işleç önceliğinin motora bağlılığı.

Önceki ders gruplamayı kurdu: tek bir sorgunun ürettiği satırlar kümelere ayrıldı ve her
küme özetlendi. Birleştirme ile gruplama, hep tek bir sorgu içinde çalıştı.

Kimi soru ise iki ayrı sorgunun sonuçlarını karşılaştırmayı ister. "Bu iki listede ortak
olanlar", "birincide olup ikincide olmayanlar", "iki listenin toplamı" — üçü de küme
kuramının işlemleridir ve SQL'de doğrudan karşılıkları vardır. Bu ders o işlemleri kurar.

Ayrımı baştan koymak gerekir: birleştirme satırları **yan yana** ekler, sütun sayısını
artırır. Küme işlemleri satırları **alt alta** ekler, sütun sayısını değiştirmez.

Aşağıdaki blok şemayı ve örnek veriyi kurar; dersin bütün sorguları bu blokta oluşturulan
`kutuphane.db` dosyası üzerinde çalışır.

```sh
rm -f kutuphane.db
sqlite3 kutuphane.db <<'SQL'
CREATE TABLE sube (sube_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, sehir TEXT NOT NULL);
CREATE TABLE kitap (kitap_id INTEGER PRIMARY KEY, baslik TEXT NOT NULL, yazar TEXT NOT NULL,
                    basim_yili INTEGER, sube_id INTEGER REFERENCES sube(sube_id));
CREATE TABLE uye (uye_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, soyad TEXT NOT NULL,
                  eposta TEXT, kayit_tarihi TEXT NOT NULL);
CREATE TABLE odunc (odunc_id INTEGER PRIMARY KEY, kitap_id INTEGER NOT NULL REFERENCES kitap(kitap_id),
                    uye_id INTEGER NOT NULL REFERENCES uye(uye_id), alis_tarihi TEXT NOT NULL,
                    iade_tarihi TEXT);
INSERT INTO sube VALUES (1,'Merkez','Ankara'),(2,'Bahçelievler','Ankara'),
  (3,'Kadıköy','İstanbul'),(4,'Konak','İzmir');
INSERT INTO kitap VALUES (1,'Körlük','José Saramago',1995,1),(2,'Tutunamayanlar','Oğuz Atay',1972,1),
  (3,'Kum Kitabı','Jorge Luis Borges',1975,2),(4,'Yaban','Yakup Kadri',1932,2),
  (5,'Sessiz Ev','Orhan Pamuk',1983,3),(6,'Anayurt Oteli','Yusuf Atılgan',NULL,3),
  (7,'Tehlikeli Oyunlar','Oğuz Atay',1973,NULL);
INSERT INTO uye VALUES (1,'Ayşe','Demir','ayse@ornek.test','2023-02-14'),
  (2,'Mehmet','Kaya','mehmet@ornek.test','2023-05-30'),(3,'Zeynep','Arslan',NULL,'2024-01-09'),
  (4,'Emre','Yıldız','emre@ornek.test','2024-03-22'),(5,'Selin','Aydın',NULL,'2024-11-05'),
  (6,'Burak','Şahin','burak@ornek.test','2025-01-18');
INSERT INTO odunc VALUES (1,1,1,'2025-01-10','2025-01-24'),(2,2,1,'2025-02-02','2025-02-20'),
  (3,1,2,'2025-02-11',NULL),(4,3,3,'2025-03-01','2025-03-15'),(5,4,3,'2025-03-18','2025-04-02'),
  (6,1,4,'2025-04-05','2025-04-19'),(7,5,4,'2025-04-21',NULL),(8,2,5,'2025-05-02','2025-05-30'),
  (9,7,1,'2025-05-14','2025-05-28'),(10,3,5,'2025-06-03',NULL),(11,6,2,'2025-06-11','2025-06-25'),
  (12,4,4,'2025-06-20','2025-07-04');
SQL
```

## İki Sonuç Kümesi

Örnekler boyunca iki sorgu kullanılacak. Birincisi 1980 öncesi basılmış kitapların
yazarlarını, ikincisi merkez şubedeki kitapların yazarlarını veriyor.

```sh
sqlite3 kutuphane.db <<'SQL'
.headers on
.mode column
SELECT yazar FROM kitap WHERE basim_yili < 1980 ORDER BY yazar;
SELECT yazar FROM kitap WHERE sube_id = 1 ORDER BY yazar;
SQL
```

```
yazar            
-----------------
Jorge Luis Borges
Oğuz Atay        
Oğuz Atay        
Yakup Kadri      
yazar        
-------------
José Saramago
Oğuz Atay    
```

Birinci küme dört satır ve içinde bir yineleme var — aynı yazarın iki kitabı da 1980
öncesi. İkinci küme iki satır. Ortak değer `Oğuz Atay`.

İki sorgunun küme işlemiyle birleştirilebilmesi için **birleşim uyumlu** (union compatible)
olmaları gerekir: sütun sayıları eşit ve karşılıklı sütunların tipleri karşılaştırılabilir
olmalı. Sayı eşit değilse sorgu çalışmaz.

```sh
sqlite3 kutuphane.db <<'SQL'
.headers on
.mode column
SELECT baslik FROM kitap
UNION
SELECT ad, sehir FROM sube;
SQL
```

```
Parse error near line 3: SELECTs to the left and right of UNION do not have the same number of result columns
```

Sonuçtaki sütun adları **ilk sorgudan** alınır; sonraki sorguların takma adları göz ardı
edilir.

## Birleşim ve Yinelenen Satırlar

Birleşim iki kümenin satırlarını alt alta koyar. İki yazımı vardır ve aralarındaki tek
fark yinelenen satırlara ne olduğudur.

```sh
sqlite3 kutuphane.db <<'SQL'
.headers on
.mode column
SELECT yazar FROM kitap WHERE basim_yili < 1980
UNION
SELECT yazar FROM kitap WHERE sube_id = 1
ORDER BY yazar;
SQL
```

```
yazar            
-----------------
Jorge Luis Borges
José Saramago    
Oğuz Atay        
Yakup Kadri      
```

Dört artı iki, altı satır bekleniyordu; dört satır döndü. `UNION` yinelenen satırları
**eler** — hem iki küme arasındaki ortak satırı, hem de tek bir kümenin içindeki
yinelemeyi. `Oğuz Atay` üç kez geçtiği halde bir kez göründü.

```sh
sqlite3 kutuphane.db <<'SQL'
.headers on
.mode column
SELECT yazar FROM kitap WHERE basim_yili < 1980
UNION ALL
SELECT yazar FROM kitap WHERE sube_id = 1
ORDER BY yazar;
SQL
```

```
yazar            
-----------------
Jorge Luis Borges
José Saramago    
Oğuz Atay        
Oğuz Atay        
Oğuz Atay        
Yakup Kadri      
```

`UNION ALL` hiçbir şey elemedi: altı satır. Bu ayrım yalnız bir sonuç farkı değil, bir
maliyet farkıdır. Yineleme elemek için motorun bütün satırları karşılaştırması gerekir —
sıralama ya da karma tablosu kurar. `UNION ALL` böyle bir iş yapmaz.

Seçim açık olmalıdır: yinelemenin gerçekten elenmesi gerekiyorsa `UNION`, gerekmiyorsa
`UNION ALL`. Ayrık oldukları bilinen iki kümeyi `UNION` ile birleştirmek, hiçbir işe
yaramayan bir eleme maliyeti öder. Ters yönde, yinelemenin elenmesi gerekirken `UNION ALL`
yazmak sessizce şişmiş sayımlar üretir.

## Kesişim ve Fark

Kesişim, iki kümede de bulunan satırları verir.

```sh
sqlite3 kutuphane.db <<'SQL'
.headers on
.mode column
SELECT yazar FROM kitap WHERE basim_yili < 1980
INTERSECT
SELECT yazar FROM kitap WHERE sube_id = 1;
SQL
```

```
yazar    
---------
Oğuz Atay
```

Fark, birinci kümede olup ikincide olmayan satırları verir.

```sh
sqlite3 kutuphane.db <<'SQL'
.headers on
.mode column
SELECT yazar FROM kitap WHERE basim_yili < 1980
EXCEPT
SELECT yazar FROM kitap WHERE sube_id = 1;
SQL
```

```
yazar            
-----------------
Jorge Luis Borges
Yakup Kadri      
```

Fark işlemi **yönlüdür**: sıra değiştirildiğinde sonuç değişir. Kesişim ve birleşim
yönsüzdür.

İki işlem de öntanımlı olarak yinelenen satırları eler. Yinelemeyi koruyan biçimleri
standartta tanımlıdır ama desteği **motora göre değişir**.

```sh
sqlite3 kutuphane.db <<'SQL'
.headers on
.mode column
SELECT yazar FROM kitap WHERE basim_yili < 1980
INTERSECT ALL
SELECT yazar FROM kitap WHERE sube_id = 1;
SQL
```

```
Parse error near line 3: near "ALL": syntax error
  azar FROM kitap WHERE basim_yili < 1980 INTERSECT ALL SELECT yazar FROM kitap 
                                      error here ---^
```

Fark işleminin **adı da motora göre değişir**: bazı motorlarda `EXCEPT` yerine başka bir
anahtar sözcük kullanılır. Taşınabilirlik gerekiyorsa küme işlemleri, adları ve
seçenekleriyle birlikte hedef motorda sınanmalıdır.

## Boş Değer Küme İşlemlerinde Eşittir

Beşinci derste ölçülen tuzak hatırlanmalı: `NOT IN` listesindeki tek bir boş değer sorguyu
sıfır satıra düşürüyordu. Küme işlemleri aynı tuzağı taşımaz, çünkü boş değerleri
gruplamanın yaptığı gibi **birbirine eşit** sayarlar.

```sh
sqlite3 kutuphane.db <<'SQL'
.headers on
.mode box
SELECT NULL AS birlesim UNION SELECT NULL;
SELECT NULL AS birlesim_tumu UNION ALL SELECT NULL;
SQL
```

```
┌──────────┐
│ birlesim │
├──────────┤
│          │
└──────────┘
┌───────────────┐
│ birlesim_tumu │
├───────────────┤
│               │
│               │
└───────────────┘
```

Çerçeveli çıktı biçimi burada satır sayısını görünür kılıyor: iki boş değer birleşimde tek
satıra indi, `UNION ALL` yazımında iki satır kaldı. Boş değer, karşılaştırma işleci
açısından kendisine eşit değildir ama küme işlemleri açısından eşittir.

Bunun doğrudan bir sonucu var: "hangi şubede hiç kitap yok" sorusu fark işlemiyle
yazıldığında, kitap tablosundaki boş şube kimliği sonucu bozmaz.

```sh
sqlite3 kutuphane.db <<'SQL'
.headers on
.mode column
SELECT sube_id FROM sube
EXCEPT
SELECT sube_id FROM kitap;
SQL
```

```
sube_id
-------
4      
```

Doğru yanıt tek satır. Aynı soru `NOT IN` ile yazılsaydı, kitap tablosundaki boş kimlik
yüzünden hiçbir satır dönmeyecekti. Fark işlemi, boş değerli sütunlarda `NOT IN` yazımına
göre daha güvenli bir seçenektir.

## Öncelik ve Sıralama

Birden çok küme işlecinin aynı deyimde kullanılması durumunda değerlendirme sırası önem
kazanır. Standart, kesişime birleşim ve farktan daha yüksek öncelik verir. Uygulaması
**motora göre değişir**.

```sh
sqlite3 kutuphane.db <<'SQL'
.headers on
.mode column
SELECT yazar FROM kitap WHERE sube_id = 1
UNION
SELECT yazar FROM kitap WHERE basim_yili < 1980
INTERSECT
SELECT yazar FROM kitap WHERE basim_yili > 1980;
SQL
```

```
yazar        
-------------
José Saramago
```

Bu motor işleçleri soldan sağa uyguladı: önce birleşim, sonra kesişim. Kesişim önce
uygulansaydı ikinci ve üçüncü küme ortak satır taşımadığı için boş kalır, birleşim ilk
kümeyi olduğu gibi döndürür ve sonuç iki satır olurdu. Ayraçla gruplamak da her yerde
kabul edilmez.

```sh
sqlite3 kutuphane.db <<'SQL'
.headers on
.mode column
SELECT yazar FROM kitap WHERE sube_id = 1
UNION
(SELECT yazar FROM kitap WHERE basim_yili < 1980
 INTERSECT
 SELECT yazar FROM kitap WHERE basim_yili > 1980);
SQL
```

```
Parse error near line 3: near "(": syntax error
  SELECT yazar FROM kitap WHERE sube_id = 1 UNION (SELECT yazar FROM kitap WHERE
                                    error here ---^
```

Sonuç olarak, farklı küme işleçlerini tek deyimde karıştırmak taşınabilir bir yazım
değildir. Karışık kullanım gerektiğinde ara sonuçları adlandıran yapılar — İleri SQL
kursundaki ortak tablo ifadeleri — hem sırayı belirginleştirir hem de sorguyu okunur kılar.

Sıralamada da bir kural var: `ORDER BY` yan tümcesi tek tek sorgulara değil, **birleşik
sonucun tamamına** uygulanır ve deyimin sonunda tek kez yazılır. Bu yüzden sıralama
anahtarı, ilk sorgunun ürettiği sütun adlarıyla anılır.

## Özet

- Birleştirme satırları yan yana, küme işlemleri alt alta ekler; küme işlemleri sütun
  sayısını değiştirmez.
- Küme işlemine giren sorgular birleşim uyumlu olmalıdır; sütun adları ilk sorgudan alınır.
- `UNION` yinelenen satırları eler ve bunun için karşılaştırma maliyeti öder; `UNION ALL`
  hiçbir şey elemez.
- Kesişim ve fark öntanımlı olarak yinelemeleri eler; yinelemeyi koruyan biçimlerin ve
  fark işlecinin adının desteği motora göre değişir.
- Küme işlemleri boş değerleri birbirine eşit sayar; bu, fark işlemini `NOT IN` yazımına
  göre daha güvenli kılar.
- Farklı küme işleçlerinin tek deyimdeki önceliği motora göre değişir; `ORDER BY` birleşik
  sonucun tamamına uygulanır.

## Sonraki Adım

Bu konu boyunca yapılan her şey okumaydı: var olan satırlar seçildi, süzüldü, birleştirildi,
özetlendi, kümelendi. Veri hep oradaydı — ilk derste bir kez yazıldı ve bir daha
değiştirilmedi. Sıra veriyi ve onu tutan şemanın kendisini yazmakta. Sonraki konunun ilk
dersi tablo oluşturmayı ele alır: sütun tanımları, tip seçimi ve kısıtların şemada nasıl
ifade edildiği. İlişkisel Kuram kursunda kâğıt üzerinde tasarlanan bütünlük kuralları,
orada çalışan bir tanıma dönüşür.
