Skip to content

December 5, 2010

32

MySQL Join (LEFT, RIGHT, INNER, CROSS) Kullanımı ve Örnekleri

Merhaba arkadaşlar, bu yazımızda MySQL üzerinde LEFT JOIN, RIGHT JOIN, INNER JOIN ve CROSS JOIN kullanımını örneklerle birlikte inceleyeceğiz.

Join Nedir (Wiki: en) ?

Kısaca join; birbiriyle alakalı olan iki veya daha fazla tablolardan tek seferde veri çekme/filtreleme/sıralama işlemine yaramaktadır.

Join Kullanırken Yapılan En Büyük Hata Sütun Veri Tip ve Uzunluklarının Farklı Olmasıdır :

Evet, join yapılacak tabloların tablolar arası bağlantıyı kuran sütunların veri tipleri ve veri uzunlukları birbirinden farklıysa join kullanmak sorguyu çok uzatır ve performans kaybı yaşarsınız (yazımızın üçüncü sayfasından itibareb detaylar mevcut).

Örnek Senaryo :

Dört adet tablomuz olsun bunlardan ilki ürün listesi tutan urun tablosu, ikinci tablomuz ise ürünlerin detaylarını tutan urun_detay tablosu, üçüncü tablo firmamıza kayıtlı olan müşterileri tutacak olan musteri tablosu, son tablomuzda müşterilerimize satış yaptığımız ürünlerin kaydını tutan tablo satis olsun.

Firmam Veritabanı Sablonu:

Firmam Veritabanı SQL Kodu:

SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';

CREATE SCHEMA IF NOT EXISTS `firmam` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ;
SHOW WARNINGS;
USE `firmam` ;

-- -----------------------------------------------------
-- Table `firmam`.`musteri`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `firmam`.`musteri` ;

SHOW WARNINGS;
CREATE  TABLE IF NOT EXISTS `firmam`.`musteri` (
 `musteri_id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'müşteri id (auto)' ,
 `musteri_ad` VARCHAR(50) NOT NULL COMMENT 'müşterinin adı' ,
 `musteri_soyad` VARCHAR(80) NOT NULL COMMENT 'müşterinin soyadı' ,
 `musteri_telefon` INT UNSIGNED NOT NULL COMMENT 'müşterinin telefon numarası (alan kodu ile)' ,
 `musteri_email` VARCHAR(100) NULL DEFAULT NULL COMMENT 'müşterinin email adresi' ,
 `musteri_durum` ENUM('AKTIF','DEAKTIF') NOT NULL DEFAULT 'AKTIF' COMMENT 'müşteri durumu çalışılıyor yada çalışılmıyor' ,
 PRIMARY KEY (`musteri_id`) )
ENGINE = InnoDB
COMMENT = 'Müşterilerin bilgileri';

SHOW WARNINGS;
CREATE INDEX `musteri_ad_idx` ON `firmam`.`musteri` (`musteri_ad` ASC) ;

SHOW WARNINGS;
CREATE INDEX `musteri_soyad_idx` ON `firmam`.`musteri` (`musteri_soyad` ASC) ;

SHOW WARNINGS;
CREATE INDEX `musteri_durum_idx` ON `firmam`.`musteri` (`musteri_durum` ASC) ;

SHOW WARNINGS;

-- -----------------------------------------------------
-- Table `firmam`.`musteri_detay`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `firmam`.`musteri_detay` ;

SHOW WARNINGS;
CREATE  TABLE IF NOT EXISTS `firmam`.`musteri_detay` (
 `musteri_id` INT UNSIGNED NOT NULL COMMENT 'müşteri id (fk)' ,
 `musteri_detay_ulke` CHAR(2) NOT NULL COMMENT 'müşteri ülke kodu' ,
 `musteri_detay_sehir` VARCHAR(45) NOT NULL COMMENT 'müşteri şehir adı' ,
 `musteri_detay_ilce` VARCHAR(45) NULL DEFAULT NULL COMMENT 'müşteri ilçe adı' ,
 `musteri_detay_postakodu` VARCHAR(45) NULL DEFAULT NULL COMMENT 'müşteri postakodu' ,
 `musteri_detay_adres` VARCHAR(45) NULL DEFAULT NULL COMMENT 'müşteri açık adres' ,
 `musteri_detay_website` VARCHAR(45) NULL DEFAULT NULL COMMENT 'müşteri website adresi' ,
 PRIMARY KEY (`musteri_id`) ,
 CONSTRAINT `musteri_detay_musteri_id_fkey`
 FOREIGN KEY (`musteri_id` )
 REFERENCES `firmam`.`musteri` (`musteri_id` )
 ON DELETE CASCADE
 ON UPDATE CASCADE)
ENGINE = InnoDB
COMMENT = 'Müşteri detay bilgileri';

SHOW WARNINGS;
CREATE INDEX `musteri_detay_musteri_id_fkey` ON `firmam`.`musteri_detay` (`musteri_id` ASC) ;

SHOW WARNINGS;
CREATE INDEX `musteri_detay_ulke_idx` ON `firmam`.`musteri_detay` (`musteri_detay_ulke` ASC) ;

SHOW WARNINGS;
CREATE INDEX `musteri_detay_website_idx` ON `firmam`.`musteri_detay` (`musteri_detay_website` ASC) ;

SHOW WARNINGS;

-- -----------------------------------------------------
-- Table `firmam`.`urun`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `firmam`.`urun` ;

SHOW WARNINGS;
CREATE  TABLE IF NOT EXISTS `firmam`.`urun` (
 `urun_id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ürün id (auto)' ,
 `urun_adi` VARCHAR(80) NOT NULL COMMENT 'ürün adı' ,
 `urun_marka` VARCHAR(45) NOT NULL COMMENT 'ürün markası' ,
 `urun_model` VARCHAR(45) NOT NULL COMMENT 'ürün modeli' ,
 `urun_uretim` DATE NOT NULL COMMENT 'ürün üretim tarihi' ,
 PRIMARY KEY (`urun_id`) )
ENGINE = InnoDB
COMMENT = 'Ürün tablosu';

SHOW WARNINGS;
CREATE INDEX `urun_adi_idx` ON `firmam`.`urun` (`urun_adi` ASC) ;

SHOW WARNINGS;
CREATE INDEX `urun_marka_idx` ON `firmam`.`urun` (`urun_marka` ASC) ;

SHOW WARNINGS;
CREATE INDEX `urun_uretim_idx` ON `firmam`.`urun` (`urun_uretim` ASC) ;

SHOW WARNINGS;

-- -----------------------------------------------------
-- Table `firmam`.`satis`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `firmam`.`satis` ;

SHOW WARNINGS;
CREATE  TABLE IF NOT EXISTS `firmam`.`satis` (
 `satis_id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'satış id (auto)' ,
 `urun_id` INT UNSIGNED NOT NULL COMMENT 'satılan ürün id (fk)' ,
 `musteri_id` INT UNSIGNED NOT NULL COMMENT 'ürün satılan müşteri id (fk)' ,
 `satis_birim` FLOAT UNSIGNED NOT NULL COMMENT 'birim fiyatı' ,
 `satis_miktar` INT UNSIGNED NOT NULL COMMENT 'satış miktarı (adet)' ,
 `satis_tutar` FLOAT UNSIGNED NOT NULL COMMENT 'toplam tutar (TL)' ,
 `satis_tarih` DATETIME NOT NULL COMMENT 'satış tarihi' ,
 PRIMARY KEY (`satis_id`) ,
 CONSTRAINT `satis_urun_id_fkey`
 FOREIGN KEY (`urun_id` )
 REFERENCES `firmam`.`urun` (`urun_id` )
 ON DELETE CASCADE
 ON UPDATE CASCADE,
 CONSTRAINT `satis_musteri_id_fkey`
 FOREIGN KEY (`musteri_id` )
 REFERENCES `firmam`.`musteri` (`musteri_id` )
 ON DELETE CASCADE
 ON UPDATE CASCADE)
ENGINE = InnoDB
COMMENT = 'Ürün satış tablosu';

SHOW WARNINGS;
CREATE INDEX `satis_urun_id_fkey` ON `firmam`.`satis` (`urun_id` ASC) ;

SHOW WARNINGS;
CREATE INDEX `satis_musteri_id_fkey` ON `firmam`.`satis` (`musteri_id` ASC) ;

SHOW WARNINGS;
CREATE INDEX `satis_miktar_idx` ON `firmam`.`satis` (`satis_miktar` ASC) ;

SHOW WARNINGS;
CREATE INDEX `satis__tarih_idx` ON `firmam`.`satis` (`satis_tarih` ASC) ;

SHOW WARNINGS;

SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;

Firmam Veritabanı Kaynak Kodları:

Veritabanı tasarımında MySQL Workbench kullandık. Kaynak dosyayı buradan indirebilirsiniz.

Firmam Veritabanı Müşteri (musteri)  Tablosu Örnek Kayıtlar:

INSERT INTO `firmam`.`musteri` (
`musteri_id` ,
`musteri_ad` ,
`musteri_soyad` ,
`musteri_telefon` ,
`musteri_email` ,
`musteri_durum`
)
VALUES (
NULL , 'Ahmet',   'AY',      '02125555555', '[email protected]',       'AKTIF'
), (
NULL , 'Mehmet',  'YILDIZ',  '02125555556', '[email protected]',       'AKTIF'
), (
NULL , 'Ali',     'KİBAR',   '02125555557', '[email protected]',       'AKTIF'
), (
NULL , 'Mustafa', 'KIRIMLI', '05555555555', '[email protected]', 'AKTIF'
), (
NULL , 'John',    'DOE',     '02127777777', '[email protected]',        'AKTIF'
), (
NULL , 'Jane',    'DOE',     '02128888888', '[email protected]',        'DEAKTIF'
)

Firmam Veritabanı Müşteri Detay (musteri_detay) Tablosu Örnek Kayıtlar:

INSERT INTO `musteri_detay` (
`musteri_id` ,
`musteri_detay_ulke` ,
`musteri_detay_sehir` ,
`musteri_detay_ilce` ,
`musteri_detay_postakodu` ,
`musteri_detay_adres` ,
`musteri_detay_website`
)
VALUES (
 1, 'US', 'New York', NULL , NULL , NULL , NULL
) , (
 4, 'TR', 'İstanbul', NULL , NULL , NULL , 'http://mustafakirimli.com' )

Firmam Veritabanı Ürün (urun) Tablosu Örnek Kayıtlar:

INSERT INTO `firmam`.`urun` (
`urun_id` ,
`urun_adi` ,
`urun_marka` ,
`urun_model` ,
`urun_uretim`
)
VALUES (
NULL , 'Asus Notebook B43 4GB', 'Asus', 'B43', '2010-04-01'
), (
NULL , 'Asus Notebook N51V 4GB', 'Asus', 'N51V', '2009-12-01'
);

Firmam Veritabanı Satış (satis) Tablosu Örnek Kayıtlar:

INSERT INTO `firmam`.`satis` (
`satis_id` ,
`urun_id` ,
`musteri_id` ,
`satis_birim` ,
`satis_miktar` ,
`satis_tutar` ,
`satis_tarih`
)
VALUES (
NULL , '1', '5', '100', '40', '4000', '2010-12-01 10:00:00'
), (
NULL , '1', '5', '150', '10', '1500', '2010-12-02 10:00:00'
), (
NULL , '1', '4', '170', '10', '1700', '2010-12-02 11:00:00'
), (
NULL , '1', '5', '140', '10', '1400', '2010-12-02 12:00:00'
), (
NULL , '1', '6', '100', '10', '1000', '2010-12-03 10:00:00'
), (
NULL , '2', '5', '100', '30', '3000', '2010-12-03 12:00:00'
), (
NULL , '2', '5', '100', '20', '2000', '2010-12-03 13:00:00'
), (
NULL , '2', '2', '180', '10', '1000', '2010-12-03 14:00:00'
), (
NULL , '2', '2', '100', '10', '1000', '2010-12-03 15:00:00'
), (
NULL , '2', '3', '100', '30', '3000', '2010-12-03 16:41:00'
), (
NULL , '2', '3', '120', '20', '2400', '2010-12-03 16:58:00'
), (
NULL , '2', '4', '100', '30', '3000', '2010-12-03 17:15:00'
), (
NULL , '2', '1', '100', '10', '1000', '2010-12-03 17:30:00'
);

Firmam Veritabanındaki Veriler

Müşteri (musteri) Tablosu:

SELECT * FROM `firmam`.`musteri`;
+------------+------------+---------------+-----------------+-------------------------+---------------+
| musteri_id | musteri_ad | musteri_soyad | musteri_telefon | musteri_email           | musteri_durum |
+------------+------------+---------------+-----------------+-------------------------+---------------+
|          1 | Ahmet      | AY            |      2125555555 | [email protected]       | AKTIF         |
|          2 | Mehmet     | YILDIZ        |      2125555556 | [email protected]       | AKTIF         |
|          3 | Ali        | KİBAR         |      2125555557 | [email protected]       | AKTIF         |
|          4 | Mustafa    | KIRIMLI       |      4294967295 | [email protected] | AKTIF         |
|          5 | John       | DOE           |      2127777777 | [email protected]        | AKTIF         |
|          6 | Jane       | DOE           |      2128888888 | [email protected]        | DEAKTIF       |
+------------+------------+---------------+-----------------+-------------------------+---------------+
6 rows in set

Müşteri Detay (musteri_detay) Tablosu:

SELECT * FROM `firmam`.`musteri_detay`;
+------------+--------------------+---------------------+--------------------+-------------------------+---------------------+---------------------------+
| musteri_id | musteri_detay_ulke | musteri_detay_sehir | musteri_detay_ilce | musteri_detay_postakodu | musteri_detay_adres | musteri_detay_website     |
+------------+--------------------+---------------------+--------------------+-------------------------+---------------------+---------------------------+
|          1 | US                 | New York            | NULL               | NULL                    | NULL                | NULL                      |
|          4 | TR                 | İstanbul            | NULL               | NULL                    | NULL                | http://mustafakirimli.com |
+------------+--------------------+---------------------+--------------------+-------------------------+---------------------+---------------------------+
2 rows in set

Ürün (urun) Tablosu:

SELECT * FROM `firmam`.`urun`;
+---------+------------------------+------------+------------+-------------+
| urun_id | urun_adi               | urun_marka | urun_model | urun_uretim |
+---------+------------------------+------------+------------+-------------+
|       1 | Asus Notebook B43 4GB  | Asus       | B43        | 2010-04-01  |
|       2 | Asus Notebook N51V 4GB | Asus       | N51V       | 2009-12-01  |
+---------+------------------------+------------+------------+-------------+
2 rows in set

Satış (satis) Tablosu:

SELECT * FROM `firmam`.`satis`;
+----------+---------+------------+-------------+--------------+-------------+---------------------+
| satis_id | urun_id | musteri_id | satis_birim | satis_miktar | satis_tutar | satis_tarih         |
+----------+---------+------------+-------------+--------------+-------------+---------------------+
|        1 |       1 |          5 |         100 |           40 |        4000 | 2010-12-01 10:00:00 |
|        2 |       1 |          5 |         100 |           10 |        1000 | 2010-12-02 10:00:00 |
|        3 |       1 |          5 |         100 |           40 |        4000 | 2010-12-01 10:00:00 |
|        4 |       1 |          5 |         150 |           10 |        1500 | 2010-12-02 10:00:00 |
|        5 |       1 |          4 |         170 |           10 |        1700 | 2010-12-02 11:00:00 |
|        6 |       1 |          5 |         140 |           10 |        1400 | 2010-12-02 12:00:00 |
|        7 |       1 |          6 |         100 |           10 |        1000 | 2010-12-03 10:00:00 |
|        8 |       2 |          5 |         100 |           30 |        3000 | 2010-12-03 12:00:00 |
|        9 |       2 |          5 |         100 |           20 |        2000 | 2010-12-03 13:00:00 |
|       10 |       2 |          2 |         180 |           10 |        1000 | 2010-12-03 14:00:00 |
|       11 |       2 |          2 |         100 |           10 |        1000 | 2010-12-03 15:00:00 |
|       12 |       2 |          3 |         100 |           30 |        3000 | 2010-12-03 16:41:00 |
|       13 |       2 |          3 |         120 |           20 |        2400 | 2010-12-03 16:58:00 |
|       14 |       2 |          4 |         100 |           30 |        3000 | 2010-12-03 17:15:00 |
|       15 |       2 |          1 |         100 |           10 |        1000 | 2010-12-03 17:30:00 |
+----------+---------+------------+-------------+--------------+-------------+---------------------+
15 rows in set

INNER JOIN Kullanımı:

İlk olarak en yaygın kullanılan JOIN tipi olan INNER JOIN ‘i inceleyeceğiz. INNER JOIN seçtiğiniz tablolarda birebir eşleşen kayıtları getirir. Örneğin musteri ve musteri_detay tablolarını inceleyecek olursanız 6 adet müşteri kaydımız ve 2 adet müşteri detay kaydımız bulunuyor. Biz bu tablolar için INNER JOIN kullanırsak bize sadece 2 satır kayıt dönecektir. Çünkü her iki tabloda kaydı bulunan musteri sadece 2 tanedir.

Örnek INNER JOIN Sorgusu :

SELECT m.*, md.musteri_detay_website
FROM firmam.musteri AS m
INNER JOIN firmam.musteri_detay AS md ON m.musteri_id = md.musteri_id

Örnek INNER JOIN Sorgu Sonucu :

+------------+------------+---------------+-----------------+-------------------------+---------------+---------------------------+
| musteri_id | musteri_ad | musteri_soyad | musteri_telefon | musteri_email           | musteri_durum | musteri_detay_website     |
+------------+------------+---------------+-----------------+-------------------------+---------------+---------------------------+
|          1 | Ahmet      | AY            |      2125555555 | [email protected]       | AKTIF         | NULL                      |
|          4 | Mustafa    | KIRIMLI       |      4294967295 | [email protected] | AKTIF         | http://mustafakirimli.com |
+------------+------------+---------------+-----------------+-------------------------+---------------+---------------------------+
2 rows in set (0.00 sec)

Yukarıdaki sorgumuzda sonuç sütunlarının ekrana sığması açısından musteri tablosundaki tüm sütunları, musteri_detay tablosundaki musteri_detay_website sütununu seçtik. Siz isterseniz “*” kullanarak hepsini seçebilirsiniz. Zaten büyük tablololarda performans kazanmak için gerekmeyen sütunların seçilmemesi önerilir.

INNER JOIN kullanarak bir örnek daha yapmış olalım. Bizden İstanbul ‘da olan müşterilerin adı, soyadı ve telefon bilgileri isteniyor olsun. Sorgumuz aşağıdaki gibi olacaktır.

SELECT m.musteri_ad, m.musteri_soyad, m.musteri_telefon
FROM firmam.musteri AS m
INNER JOIN firmam.musteri_detay AS md ON m.musteri_id = md.musteri_id
WHERE md.musteri_detay_sehir =  'İstanbul'

Sorgunun sonucu aşağıdaki gibidir:

+------------+---------------+-----------------+
| musteri_ad | musteri_soyad | musteri_telefon |
+------------+---------------+-----------------+
| Mustafa    | KIRIMLI       |      4294967295 |
+------------+---------------+-----------------+
1 row in set (0.00 sec)

Bir başka INNER JOIN örneği

Şimdide hem 3 tabloyu JOIN yapmayı inceleyelim hemde sorgumuzu biraz daha karşamık hale getirelim. Bizden kısaca kime, hangi ürünü, kaç adet, toplam ne kadara? sorularının SQL sonuçlarını istiyor olsunlar.

Burada yapacağımız şey satış tablosundan yola çıkarak müşteri bilgilerini almak için müşteri tablosunu satış tablosuna  JOIN yapmak ve daha sonra  ürün bilgilerini almak için ürün tablosunu satış tablosuna JOIN yapmak olacak.

SELECT m.musteri_ad, m.musteri_soyad, m.musteri_telefon, u.urun_adi, s.satis_miktar, s.satis_tutar
FROM firmam.satis AS s
INNER JOIN firmam.musteri AS m ON s.musteri_id = m.musteri_id
INNER JOIN firmam.urun AS u ON s.urun_id = u.urun_id
WHERE 1
ORDER BY m.musteri_id

Sorgu Sonucu :

+------------+---------------+-----------------+------------------------+--------------+-------------+
| musteri_ad | musteri_soyad | musteri_telefon | urun_adi               | satis_miktar | satis_tutar |
+------------+---------------+-----------------+------------------------+--------------+-------------+
| Ahmet      | AY            |      2125555555 | Asus Notebook N51V 4GB |           10 |        1000 |
| Mehmet     | YILDIZ        |      2125555556 | Asus Notebook N51V 4GB |           10 |        1000 |
| Mehmet     | YILDIZ        |      2125555556 | Asus Notebook N51V 4GB |           10 |        1000 |
| Ali        | KİBAR         |      2125555557 | Asus Notebook N51V 4GB |           30 |        3000 |
| Ali        | KİBAR         |      2125555557 | Asus Notebook N51V 4GB |           20 |        2400 |
| Mustafa    | KIRIMLI       |      4294967295 | Asus Notebook B43 4GB  |           10 |        1700 |
| Mustafa    | KIRIMLI       |      4294967295 | Asus Notebook N51V 4GB |           30 |        3000 |
| John       | DOE           |      2127777777 | Asus Notebook B43 4GB  |           10 |        1400 |
| John       | DOE           |      2127777777 | Asus Notebook N51V 4GB |           30 |        3000 |
| John       | DOE           |      2127777777 | Asus Notebook B43 4GB  |           40 |        4000 |
| John       | DOE           |      2127777777 | Asus Notebook B43 4GB  |           40 |        4000 |
| John       | DOE           |      2127777777 | Asus Notebook N51V 4GB |           20 |        2000 |
| John       | DOE           |      2127777777 | Asus Notebook B43 4GB  |           10 |        1000 |
| John       | DOE           |      2127777777 | Asus Notebook B43 4GB  |           10 |        1500 |
| Jane       | DOE           |      2128888888 | Asus Notebook B43 4GB  |           10 |        1000 |
+------------+---------------+-----------------+------------------------+--------------+-------------+
15 rows in set (0.00 sec)

JOIN İle USING Kullanımı

Tüm JOIN tiplerinde ON clause yerine USING kullanılabilir. USING kullanmanın kısıtlamaları ise her iki tabloda da aynı ada sahip sütunların olması gerekliliğidir. İlk sorgumuzu USING kullanarak yeniden yazalım.

SELECT m.*, md.musteri_detay_website
FROM firmam.musteri AS m
INNER JOIN firmam.musteri_detay AS md USING(musteri_id)

Sorgu sonucu değişmeyeceği için çıktıyı buraya yazmadık.

JOIN Kullanırken “#1052 – Column ‘column_name’ in where clause is ambiguous” Hatası Almak

Örneğin sizden musteri_id si 1 olan musterinin tüm bilgilerini isterlerse aşağıdaki sorguyu yazarak sonuca ulaşmak isteyebilirsiniz. Ancak MySQL size “#1052 – Column ‘musteri_id’ in where clause is ambiguous” hatası döner. Bunun sebebi seçilen sütunların arasında aynı adı taşıyanlar olması ve sizin buna filtre uygulamaya çalışmanızdır. Örneğin aşağıdaki örnekte musteri_id si 1 olan kaydı getir dedik ancak musteri_id her iki tabloda da bulunduğundan MySQL ‘in biraz kafası karışır. Bu örnek tam yerinde olmamakla birlikte zaten bu sorguyu doğru çalıştırması asıl bizim başımızı ağrıtabilir. Bu sebeple birden fazla tablo kullanıyorsak SELECT, WHERE, GROUP BY, ORDER vb. bölümlerinde mutlaka tablo adı yada tablo aliaslarını (lakaplarını) bebelirtmek yarayımıza olacaktır.

Yanlış Kullanım :

SELECT *
FROM firmam.musteri AS m
INNER JOIN firmam.musteri_detay AS md ON m.musteri_id = md.musteri_id
WHERE musteri_id = 1

Sorgumuzun doğru yazılmış biçimi aşağıdadır:

SELECT *
FROM firmam.musteri AS m
INNER JOIN firmam.musteri_detay AS md ON m.musteri_id = md.musteri_id
WHERE m.musteri_id = 1

LEFT JOIN Kullanımı

LEFT JOIN, seçilen tablolardan soldaki bulunan tablonun tamamını alır ve sağdaki tablodan da varsa eşleşen kayıtları alır yoksa NULL ile doldurulmuş kayıtlar döner.

Bir örnekle pekiştirmeye çalışalım. Veritabanında kayıtlı müsterileri ve varsa müşteri detay bilgilerini almamız gerektiğini varsayalım.  INNER JOIN ‘i hatırlayacak olursak her iki tabloda da musterinin bulunması zorunluluğu vardı ama LEFT JOIN kullandığınızda bu zorunluluk ortadan kalkıyor.

Müşteri ve Varsa Müşteri Detay Bilgilerini Alan SQL :

SELECT m.*, md.musteri_detay_website
FROM firmam.musteri AS m
LEFT JOIN firmam.musteri_detay AS md ON m.musteri_id = md.musteri_id
WHERE 1

Sorgu Sonucu:

+------------+------------+---------------+-----------------+-------------------------+---------------+---------------------------+
| musteri_id | musteri_ad | musteri_soyad | musteri_telefon | musteri_email           | musteri_durum | musteri_detay_website     |
+------------+------------+---------------+-----------------+-------------------------+---------------+---------------------------+
|          1 | Ahmet      | AY            |      2125555555 | [email protected]       | AKTIF         | NULL                      |
|          2 | Mehmet     | YILDIZ        |      2125555556 | [email protected]       | AKTIF         | NULL                      |
|          3 | Ali        | KİBAR         |      2125555557 | [email protected]       | AKTIF         | NULL                      |
|          4 | Mustafa    | KIRIMLI       |      4294967295 | [email protected] | AKTIF         | http://mustafakirimli.com |
|          5 | John       | DOE           |      2127777777 | [email protected]        | AKTIF         | NULL                      |
|          6 | Jane       | DOE           |      2128888888 | [email protected]        | DEAKTIF       | NULL                      |
+------------+------------+---------------+-----------------+-------------------------+---------------+---------------------------+
6 rows in set (0.00 sec)

Sorgu sonucunu bir önceki sayfada bulunan INNER JOIN örneğinde ki sonuç ile karşılaştırdığımızda 4 adet fazla kayıt döndüğünü görürüz. LEFT JOIN kullandığımızda soldaki tabloda (musteri tablosu) bulunan kayıtların tamamını alır (6 adet), sağdaki tablonun ise (musteri_detay) eşleşen kayıtlar (musteri_id ile) varsa birleştirir yoksa NULL basarak satırı doldurur.

Soldaki tablo kendisinden önce yazılan tablo anlamına gelir. Yani musteri AS m LEFT JOIN musteri_detay AS md sorgusunda musteri tablosu musteri_detay tablosundan önce yazıldığından soldaki tablo olarak anılır. Sorguyu musteri _detayAS md LEFT JOIN musteri AS m şeklinde yazarsak soldaki tablo bildiğiniz gibi musteri_detay olacaktır.

1:n Relationships (birden çoğa bağlantı) Durumunda LEFT JOIN Davranışı :

Birden çoğa bağlantılı tabloları LEFT JOIN ile birleştirdiğimizde n tarafındaki tablodaki varlık kadar satır tekrarı yapılacaktır. Bunun anlamı müşteriler tablomuz ile satış tablomuzu LEFT JOIN ile birleştirirsek müşteriye yapılan satış sayısı kadar müşteri kaydı satır tekrarlaması yapılacaktır. Biraz daha açacak olursak müşteri tablomuzda aynı musteri_id ‘si ile sadece bir adet kayıt bulunabilir. Ancak bir müşteriye birden fazla satış yapabileceğimiz için satış tablosunda birden fazla musteri_id ye sahip kayıt bulunabilir.

Bir örnekle inceleyelim:

SELECT m.musteri_id , m.musteri_ad , m.musteri_soyad , s.satis_id, s.musteri_id , s.satis_tutar
FROM firmam.musteri AS m
LEFT JOIN firmam.satis AS s ON m.musteri_id = s.musteri_id
WHERE 1

Sorgu Sonucu :

+------------+------------+---------------+----------+------------+-------------+
| musteri_id | musteri_ad | musteri_soyad | satis_id | musteri_id | satis_tutar |
+------------+------------+---------------+----------+------------+-------------+
|          1 | Ahmet      | AY            |       15 |          1 |        1000 |
|          2 | Mehmet     | YILDIZ        |       10 |          2 |        1000 |
|          2 | Mehmet     | YILDIZ        |       11 |          2 |        1000 |
|          3 | Ali        | KİBAR         |       12 |          3 |        3000 |
|          3 | Ali        | KİBAR         |       13 |          3 |        2400 |
|          4 | Mustafa    | KIRIMLI       |        5 |          4 |        1700 |
|          4 | Mustafa    | KIRIMLI       |       14 |          4 |        3000 |
|          5 | John       | DOE           |        1 |          5 |        4000 |
|          5 | John       | DOE           |        2 |          5 |        1000 |
|          5 | John       | DOE           |        3 |          5 |        4000 |
|          5 | John       | DOE           |        4 |          5 |        1500 |
|          5 | John       | DOE           |        6 |          5 |        1400 |
|          5 | John       | DOE           |        8 |          5 |        3000 |
|          5 | John       | DOE           |        9 |          5 |        2000 |
|          6 | Jane       | DOE           |        7 |          6 |        1000 |
+------------+------------+---------------+----------+------------+-------------+
15 rows in set

Yukarıdaki sorgu sonucunu inceleyecek olursak müşteri bilgilerinin tekrarladığını göreceğiz. Bizim 6 adet müşterimiz olmasına rağmen 15 adet sorgu sonucu dönmüş durumda. Önemli bir hatırlatma: buradaki sorgu sonucu sayısı sadece satış tablosunun kayıt sayısına eşit değildir. Bu tip birleştirmelerde sorgu sayısı sonucu 1 tarafındaki (musteri) tablo ile n tarafındaki (satış) tablosu arasındaki ortak kayıtlar + 1 tarafındaki (müşteri) tablodaki ortak olmayan kayıtlar şeklindedir.  Hesaplayacak olursak, satış tablosundaki kayıtların hepsini müşteri tablosuna ortak (musteri_id sinin karşılığı musteri tablosunda var) olduğunu için tamamı (15 adet) + musteri tablosunda olup satis tablosunda olmayan kayıtlar (0 adet) yani toplamda 15+0 = 15 satır.

Gelişmiş LEFT JOIN Kullanımı :

Şimdi biraz basit LEFT JOIN birleştirmelerini bir adım daha ileriye taşımak için küçük bir örnek daha yapalım. Klasik LEFT JOIN birleştirmesi aslında nette onlarca ve hatta yüzlerce bulabileceğiniz bir örnektir. Ancak detaylı bir sorgu istediğimizde (ilk zamanlarda bizimde yaşadığımız) örnek bulma konusunda zaman zaman güçlük çekilebiliyor.

Örneğimizde kayıtlı ürünlerin tam listesi ile birlikte varsa 01-12-2010 (2010-12-01 Y-m-d) tarihinde yapılan satışların bilgileri isteniyor olsun.

SELECT u.* , s.satis_miktar
FROM firmam.urun AS u
LEFT JOIN firmam.satis AS s ON u.urun_id = s.urun_id
AND s.satis_tarih BETWEEN '2010-12-01 00:00:00' AND '2010-12-01 23:59:59'
WHERE 1

Sorgu Sonucu :

+---------+------------------------+------------+------------+-------------+--------------+
| urun_id | urun_adi               | urun_marka | urun_model | urun_uretim | satis_miktar |
+---------+------------------------+------------+------------+-------------+--------------+
|       1 | Asus Notebook B43 4GB  | Asus       | B43        | 2010-04-01  |           40 |
|       1 | Asus Notebook B43 4GB  | Asus       | B43        | 2010-04-01  |           40 |
|       2 | Asus Notebook N51V 4GB | Asus       | N51V       | 2009-12-01  |         NULL |
+---------+------------------------+------------+------------+-------------+--------------+
3 rows in set (0.00 sec)

Sorgu sonucunda görüldüğü gibi 3 adet kayıt döndü. Sorguyu inceleyecek olursak ON clause kısmından sonra AND diyerek JOIN işlemine devam ettik. MySQL burada sağdaki tablodan sadece belirttiğimiz tarih aralığına uyan kayıtları seçti ve soldaki tabloya normal LEFT JOIN işlemiyle birleştirme yaptı. Eğer tarih aralığını WHERE kısmında verirseniz dönen satır sayısı 2 olacaktır.  Bu sorgu senaryosu tam olarak gerçeği yansıtmıyor gibi görülebilir ancak bazen çok gerekli bir yöntem oluyor.

Sorgudan anlaşılması gereken kısım LEFT JOIN yapılırken sağdaki tabloda kayıtların olması yada olmaması durumunun ON clause bölümüne yazılırsa devam etmesidir. WHERE clause kısmına geçtiğinizde tablo çoktan birleştirilmiştir ve siz birleştirilmiş tablo üzerinde kesin filtreleme yapıyor olursunuz. Bu sebeple yaptığınız filtre direkt olarak satırları eleyecektir.

Yukarıdaki örneğin biraz daha düzgün hali (gerçek bir rapor formatına en yakın) aşağıdaki gibidir.

SELECT u.* , SUM(s.satis_miktar) AS toplam_miktar
FROM firmam.urun AS u
LEFT JOIN firmam.satis AS s ON u.urun_id = s.urun_id
AND s.satis_tarih BETWEEN '2010-12-01 00:00:00' AND '2010-12-01 23:59:59'
WHERE 1
GROUP BY u.urun_id

Sorgu Sonucu :

+---------+------------------------+------------+------------+-------------+---------------+
| urun_id | urun_adi               | urun_marka | urun_model | urun_uretim | toplam_miktar |
+---------+------------------------+------------+------------+-------------+---------------+
|       1 | Asus Notebook B43 4GB  | Asus       | B43        | 2010-04-01  |            80 |
|       2 | Asus Notebook N51V 4GB | Asus       | N51V       | 2009-12-01  |          NULL |
+---------+------------------------+------------+------------+-------------+---------------+
2 rows in set (0.00 sec)

RIGHT JOIN Kullanımı

MySQL RIGHT JOIN, LEFT JOIN işleminin tersini yapar.  Yani seçilen tablolardan sağdaki bulunan tablonun tamamını alır ve soldaki tablodan da varsa eşleşen kayıtları alır yoksa NULL ile doldurulmuş kayıtlar döner.

İlk LEFT JOIN Örneğinin RIGHT JOIN ile Yazımı :

SELECT m.*, md.musteri_detay_website
FROM firmam.musteri AS m
RIGHT JOIN firmam.musteri_detay AS md ON m.musteri_id = md.musteri_id
WHERE 1

Sorgu Sonucu :

+------------+------------+---------------+-----------------+-------------------------+---------------+---------------------------+
| musteri_id | musteri_ad | musteri_soyad | musteri_telefon | musteri_email           | musteri_durum | musteri_detay_website     |
+------------+------------+---------------+-----------------+-------------------------+---------------+---------------------------+
|          1 | Ahmet      | AY            |      2125555555 | [email protected]       | AKTIF         | NULL                      |
|          4 | Mustafa    | KIRIMLI       |      4294967295 | [email protected] | AKTIF         | http://mustafakirimli.com |
+------------+------------+---------------+-----------------+-------------------------+---------------+---------------------------+
2 rows in set (0.01 sec)

Yukarıdaki örnekte 2 adet sorgu sonucu döndü.  Bunun sebebi RIGHT JOIN kullandığınızda tabloların sağa birleştirilmesi.  Sağdaki tablodaki (musteri_detay tablosu) tüm verileri (2 adet)  alır ve sağdaki tablo ile soldaki (musteri) tablo arasındaki ortak veriler varsa alır yoksa NULL doldurur.  Kaydı olmayan müşterinin detayı olamayacağı için soldaki tablo NULL ile doldurulmuş gelmez (tablodaki NULL olabilecek kolonlar hariç). Bu SQL başka bir deyişle müşteri detay bilgisi olan kayıtları getir demektir.

RIGHT JOIN ‘i LEFT JOIN gibi Kullanmak :

RIGHT JOIN ‘i LEFT JOIN ile karşılaştırmak istiyorsanız sorgunuzdaki tabloların yazım sırasını değiştirmemeniz gerekmektedir. Zira aşağıdaki örnek RIGHT JOIN kullanmamıza rağmen LEFT JOIN sonucunu döndürür.

SELECT m.*, md.musteri_detay_website
FROM firmam.musteri_detay AS md
RIGHT JOIN firmam.musteri AS m ON md.musteri_id = m.musteri_id
WHERE 1

Sorgu Sonucu :

+------------+------------+---------------+-----------------+-------------------------+---------------+---------------------------+
| musteri_id | musteri_ad | musteri_soyad | musteri_telefon | musteri_email           | musteri_durum | musteri_detay_website     |
+------------+------------+---------------+-----------------+-------------------------+---------------+---------------------------+
|          1 | Ahmet      | AY            |      2125555555 | [email protected]       | AKTIF         | NULL                      |
|          2 | Mehmet     | YILDIZ        |      2125555556 | [email protected]       | AKTIF         | NULL                      |
|          3 | Ali        | KİBAR         |      2125555557 | [email protected]       | AKTIF         | NULL                      |
|          4 | Mustafa    | KIRIMLI       |      4294967295 | [email protected] | AKTIF         | http://mustafakirimli.com |
|          5 | John       | DOE           |      2127777777 | [email protected]        | AKTIF         | NULL                      |
|          6 | Jane       | DOE           |      2128888888 | [email protected]        | DEAKTIF       | NULL                      |
+------------+------------+---------------+-----------------+-------------------------+---------------+---------------------------+
6 rows in set (0.00 sec)

Sonuçlarda göründüğü gibi tablo yazım sırası sonuçları etkiliyor.

CROSS JOIN Kullanımı

MySQL CROSS JOIN, INNER JOIN ile aynı işlemi yapar.

MySQL JOIN İşlemlerinin Venn Şeması İle Gösterimi

JOIN işlemlerinin Venn Şeması ile gösterimini buradan (HTML5 ile hazırlandı resim değildir)  inceleyebilirsiniz.

MySQL FULL OUTER JOIN İşlemi (MySQL FULL OUTER JOIN desteklemez simülasyon ile yapıyoruz)

MySQL ile FULL OUTER JOIN kullanmak için union, union all yada mutex table yöntemini kullanmanız gerekir. (detaylar gelecek)

FULL OUTER JOIN için kullandığım kaynak: http://www.xaprb.com/blog/2006/05/26/how-to-write-full-outer-join-in-mysql/

Toplam 32 Yorum Yorum Yaz
  1. SERDAR GÜNGÖR
    Jun 19 2011

    ÇOK TEŞEKKÜR EDERİM.
    MUHTEŞEM BİR PAYŞAŞIM OLMUŞ.

    Reply
  2. mgazi
    Sep 16 2011

    Join olayından oldum olası korktum. Öğrenemeyeceğimi sandım hep. Öğrenmek içinde ayrıntılı, püf noktalarının verildiği bir Türkçe makale bulamayacağımı sanmıştım. Ama bu yazı benim tabularımı yıktı. Çok teşekkürler.

    Reply
  3. nuknettin
    Jan 4 2012

    peki şöyle bir sorgu nasıl olur
    soldaki tabloda bir ürün var ve sağdaki tablodanda soldaki ürüne ait sadece tek bir belirlenmiş satırı getirmek istiyoruz. bunu mssql cross apply ile yapıyoruz ancak internetde çok araştırmama rağmen mysql karşılığını bulamadım. sizin bir çözümünüz varmı bununla ilgili ???

    Reply
    • Jan 4 2012

      Merhaba nuknettin,

      Tablolar 1:1 (one to one) şeklinde birbirlerine bağlıysa INNER JOIN, 1:n (one to n, one to many) olarak bağlıysa LEFT JOIN + soldaki tablo alanını GROUP BY ile olur.

      Örnek senaryo üzerinde daha iyi anlatılır bu konu. Ayrıca özette olsa tablo yapını paylaşman gerekir. Sağ tablodan hangi veriyi (hangi sırayla) alacağının önemi var mı vs.

      İyi Günler

      Reply
    • nuknettin
      Jan 4 2012

      ben örnek mssql sorgumu yazıyorum

      SELECT TOP(12) OTELADI, 
        YILDIZ, 
        ADRESI, 
        ID, 
        BOLGE, 
        BOLGE1,
        (SELECT TOP(1) RESIM1 
         FROM RESIMLER 
         WHERE (OTELTUR.ID=RESIMLER.OID) 
         ORDER BY ANARESIM,ID ASC
        ) as RESIM1,
        Fiyatlar.*,
        Liste.*,
        Kampanya.*
      FROM OTELTUR
      cross apply (
        SELECT TOP(1) PERCENT KBTUTAR, 
          HESAPTUR,
          (select IndirimOran1 
           from IndirimPlan 
           where (PlanId = INDIRIMPLAN) 
             and POSId='0' 
             AND TaksitSayisi = '0' 
             AND Durum = 1
          ) AS INDIRIM, 
          DOVIZTUR 
        FROM OTELTURDETAY 
        where OID = OTELTUR.ID 
          AND BITTARIH >= GETDATE() 
          AND (KBTUTAR > 0) 
          AND WEBGORUNMESIN '1' 
        ORDER BY BASTARIH, KBTUTAR ASC
      ) Fiyatlar
      outer apply (
        SELECT TOP(1) PERCENT KBTUTAR 
          ListeKisiBasi,
          HESAPTUR ListePansiyon,
          (select IndirimOran1
           from IndirimPlan 
           where (PlanId = INDIRIMPLAN) 
             and POSId='0' 
             AND TaksitSayisi = '0'
          ) AS ListeIndirim,
          DOVIZTUR ListeDovizTur 
        FROM OTELTURDETAY 
        where OID = OTELTUR.ID 
          AND BITTARIH >= GETDATE() 
          AND (KBTUTAR > 0) 
          AND WEBGORUNMESIN '1' 
          AND LISTE = 1 
        ORDER BY BASTARIH,KBTUTAR ASC
      ) Liste
      outer apply (
        SELECT TOP(1) 
               PERCENT Id as KampanyaId,
               TarihBitis,
               TarihBaslangic,
               TarihKonaklamaBaslangic,
               TarihKonaklamaBitis, 
               KampanyaTip,
               KampanyaAdi,
               Aciklama,
               KampanyaSart
        FROM OtelKampanyalar
        WHERE OtelId = OTELTUR.ID
          And Durum = 1
          AND(
           (TarihBaslangic>=GETDATE() 
            AND TarihBaslangic=GETDATE() 
            AND TarihBitis<=GETDATE() )
           OR
           (TarihBaslangic=GETDATE())
          )
          ORDER BY TarihBaslangic, 
               KampanyaTip, 
               KampanyaSart DESC
          ) Kampanya
      ORDER BY WEBSIRA
      

      bu veritabanını mysql e aktardım ve bu sorguyu mysql e çevirmekte sorun yaşıyorum

      Reply
    • nuknettin
      Jan 4 2012

      yani özetle ilk tablodaki otele ait 2.tablodan belirtmiş olduğum kriterlere göre ilk fiyatı, eğer varsa outer apply ile liste fiyatını ve yine outer apply ile varsa kampanyayı çekmek istiyorum yukarıdaki sql sorgusu mssql sorunsuz çalışıyor ancak mysql de bunu inner join ile japtığımda çok alakasız ve tek bir satır sonuç alabiliyorum

      Reply
    • Jan 4 2012

      MySQL ‘de bulunan çözümünüzün Subquery olduğunu düşünüyorum. FROM alanında subquery kullanmak(en).

      Ancak bu kadar subquery içeren ve bu denli büyük sorgunun performans açısından sıkıntı yaratma ihtimali yüksek sanırım.

      Reply
    • nuknettin
      Jan 4 2012

      bir deneyeceğim sonucu tekrar yazarım teşekkürler.

      Reply
    • nuknettin
      Jan 4 2012

      denedim ancak inner join ile aynı sonucu verdi sanırım sorguyu inner join ile çevirirken cross apply içinde kullandığım OTELTUR.ID = OID alanını dışarı almamdan kaynaklanıyor ancak bunu sorgunun içinde kullanmamın bir yolu yok sanırım. inner join ile çevirdiği sorgu aşağıdaki gibi ve sizin önderdiğinin sorguyuda onun altına yazıyorum sorguları biraz kısalttım çünkü bu sonucu elde edersem diğerinide çözerim sanıyorum.

      SELECT  
        Otel.OTELADI,Otel.YILDIZ,Otel.ADRESI,Otel.ID,Otel.BOLGE,Otel.BOLGE1,
        (select RESIM1 FROM RESIMLER where (Otel.ID=RESIMLER.OID) ORDER BY ANARESIM,ID ASC LIMIT 1) as RESIM1,
        Fiyatlar.*
      FROM OTELTUR as Otel
      inner join  
          (SELECT OID,KBTUTAR,HESAPTUR,(select IndirimOran1 from IndirimPlan where (PlanId = INDIRIMPLAN) and POSId='0' AND TaksitSayisi = '0' AND Durum = 1) AS INDIRIM,DOVIZTUR FROM OTELTURDETAY where BITTARIH >= '2012-01-03' AND (KBTUTAR > 0) AND WEBGORUNMESIN  '1' ORDER BY BASTARIH,KBTUTAR ASC LIMIT 1) Fiyatlar 
      on (Fiyatlar.OID = Otel.ID)       
      WHERE Otel.WEBCIKSIN = '1' 
      ORDER BY Otel.WEBSIRA 
      
      SELECT  
        Otel.OTELADI,Otel.YILDIZ,Otel.ADRESI,Otel.ID,Otel.BOLGE,Otel.BOLGE1,
        (select RESIM1 FROM RESIMLER where (Otel.ID=RESIMLER.OID) ORDER BY ANARESIM,ID ASC LIMIT 1) as RESIM1,
        Fiyatlar.*
      FROM OTELTUR as Otel, 
       (SELECT OID,KBTUTAR,HESAPTUR,(select IndirimOran1 from IndirimPlan where (PlanId = INDIRIMPLAN) and POSId='0' AND TaksitSayisi = '0' AND Durum = 1) AS INDIRIM,DOVIZTUR FROM OTELTURDETAY where BITTARIH >= '2012-01-03' AND (KBTUTAR > 0) AND WEBGORUNMESIN  '1' ORDER BY BASTARIH,KBTUTAR ASC LIMIT 1) Fiyatlar 
      
      WHERE Fiyatlar.OID = Otel.ID  AND Otel.WEBCIKSIN = '1' 
      ORDER BY Otel.WEBSIRA
      
      Reply
    • Jan 4 2012

      Tavsiyem tabloları (sort dışında) OTELTUR tablosuna direkt join yaparak duruma göre ON clause ‘da yada WHERE clause ‘da filtreleme yapmanız.

      Bu sorgu üzerinde harcadığımız tüm zaman eş zamanlı 10k üzerinde trafik aldığınızda boşa gidecektir. Eğer cache kullanacaksanız zaten bu kadar karmaşık sorguya gerek yok. İki yada üç ayrı sorguda almanızın daha yerinde olur.

      Gerçekten tek sorgu yazmanız gerekmiyorsa kullanmayın derim. Sorgudan kaçmış gibi olmamak adına; biraz zaman ayırıp çözülebileceğini tahmin ediyorum.

      İyi Günler

      Reply
    • nuknettin
      Jan 4 2012

      teşekkürler cevaplarınız için dediklerinizi bir deniyeceğim

      Reply
    • Jan 4 2012

      Rica ederim umarım işe yarar. Ayrıca WEBGOSTER “1” bu şekilde degil orjinal sorgunuz degil mi?

      Reply
    • nuknettin
      Jan 4 2012

      hayır değil sanırım burada silinmiş

      Reply
    • nuknettin
      Jan 4 2012

      sanırım sorunun kaynağını buldum kullandığım inner join içerisindeki limit sınırlaması sonucunda sadece tekbir satır sonuç döndürdüğünden sadece 1 otele ait bilgiyi çekiyor. bu nedenle sadece bir sonuç dönüyordu bunu ayrı bir view oluşturana kadar farkedemedim onun dışında sorgu gayet hızlı çalışıyor şimdi acaba bu sorunu nasıl çözebiliriz :))

      Reply
    • Jan 4 2012

      Limitsiz çektiğinizde sorunsuz çalışması gerekmiyor mu? ON clause alanında otel eşleştirmesi yapıyorsunuz.

      Hızlıdan kastınız kaç ms? Vede kaç kayıtla. Sıkıntı yaratmayacak kadar hızlıysa tebrikler. Ama sorgunuzda bir çok alanda INDEX kullanamadan JOIN yapmak zorunda kalıyor MySQL.

      Reply
    • Jan 4 2012

      Benim dediğimde olmaz muhtemelen. Sorgu içerisinde yapmak istiyorsunuz o otele ait limitlmeyi. SELECT alanında sub query ile çözmenize engel bir durum var mı?

      Reply
    • nuknettin
      Jan 4 2012

      sorgu içinde herbir row için subquery oluşturmak gerekiyor sizin dediğinizde ve inner joinde ise iç sorguda Otel.Id = Fiyatlar.OID kabul etmiyor bu yüzden en üstte bulduğu otele ait veriyi çekiyor. mysql en altta group by ifadesine izin veriyor ancak mssql sorgusu ile karşılaştırdığımda farklı sonuçlar olduğu aşikar. halen uğraşıyorum.

      Reply
    • nuknettin
      Jan 4 2012

      bu arada otel tablosnda 1900 kayıt fiyat tablosunda 40000 kayıt bulunuyor sonuç ise 0.163 sn

      Reply
    • Jan 4 2012

      40.000 kayıt için ortalamanın üzerinde bir süre. Eğer sorgu webde çalışacaksa yük altında kaynak kullanımını ölçün derim.

      Amazon.com 100ms yavaşladığında satışlarının %1 oranında düştüğünü söylüyor. “Latency matters. Amazon found every 100ms of latency cost them 1% in sales” sayfa yüklenme süresinin önemi

      Reply
    • nuknettin
      Jan 4 2012

      şuan içiçe sorgu deniyorum ancak yinede ana sorgudan gelecek id lerin içerisinde sadece fiyatı olanları çekmem gerek bu nasıl olacak group by kullanınca sorgu çok yavaşlıyor

      Reply
  4. Murat
    Mar 1 2012

    hocam makale için teşekkürler, gerçekten faydalı.

    ben çok merak ettiğim ve üzerinde çok kafa yorduğum bi durum var bilmiyorum yardımcı olabilir misiniz.

    şimdi twitter tarzı üye takip sistemi olan bir site düşünün. kimin kimi takip ettiğini “takip” isimli bir tabloda tutuyor olalım.

    takip_id—>takip_edilen_id—->takip_eden_id——>takip_tarihi

    tarzında sütunlarımız olsun.

    bir de kişilerin gerçekleştirmiş oldukları olaylara dair bir “olaylar” tablosu olsun. işte ahmet şuna yorum yaptı, mehmet şunu beğendi tarzında.

    işte benim film burda kopuyor. her üyenin duvarında, takip ettiği kişilerin yapmış olduğu olayları (bunlar farklı bir kaç tabloda da tutuluyor olabilir) tarih sırasına göre nasıl dizerim.(facebook duvar mantığı) bir türlü bu mantığı çözemedim. benim takip ettiğim onlarca kişi olabilir. o onlarca kişinin id numaralarına göre “olaylar” ve ona benzer farklı bir kaç tabloda bir defada sorgu yapıp sonuçları tarihe göre nasıl listeleticem.

    düşünmekten beynim durdu, belki de çok basit bir mantığı vardır ben bilmiyorum gerçekten bu konuda yardım ederseniz çok sevinicem.

    Reply
  5. hakan
    May 2 2012

    Merhaba Hocam,
    tek tabloda her 1 öğrencinin 42 soruya verdiği 20 bin civarında cevaptan kullanıcıları ve 42 cevabı yan yana nasıl sıralayabilirim?

    görüntüyü şurda soruya eklemiştim: http://www.uzmansorusu.com/soru/2946/inner-join-ile-birlestirme

    şimdiden tşkler. iyi çalışmalar…

    Reply
    • May 2 2012

      Merhaba Hakan bey,

      Sanırım her satırda o öğrenciye ait 42 soruyu ve cevabı almak istiyorsunuz. Bunu yapmak performans açısından çokta mantıklı olmayabilir.

      Eğer tek seferde almanız zorunlu değilse farklı satırlarda (alt alta) alıp ekrana yan yana basmak daha iyi sonuç almanızı sağlar. İllaki yapmanız gerekiyorsa group_concat, soru sayısı kadar join yapma (max join limitine takılabilirsiniz) gibi yöntemler deneyebilirsiniz. Ama size önerim gb seviyesinde ve milyona yakın kayıtta performans karşılaştırması yapmanız olacaktır.

      Saygılarımla

      Reply
  6. cemal
    May 8 2012

    merhaba merak ettiğim birşey var yardımcı olabilirseniz sevinirim
    10 tane öğrencinin bulunduğu bir sınıf var fakat bu öğrencilerin hepsi 20 dersten farklı dersleri alyor atıyorum 2şer ders alıyorlar.bu derslerdende 4 er sınav olmuşlar. ben tek tabloda bir öğrencinin aldığı derslerin sınav toplamlarını gösterebilirmiyim

    Reply
  7. bir
    Jun 1 2012

    bir join kullanımı arıyordum nerelere geldim ya. neyin kafası yaa bu…

    Reply
  8. omerit
    Nov 12 2012

    merhaba güzel makale, tebrikler.

    şöylebir sorunum var.
    diyelim ki; urunler ve gruplar şeklinde tablolalarımız var.

    CREATE TABLE IF NOT EXISTS `grup` (
    `urunid` mediumint(8) NOT NULL,
    `grup` int(2) NOT NULL,
    PRIMARY KEY (`urunid`),
    KEY `grup` (`grup`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

    INSERT INTO `grup` (`urunid`, `grup`) VALUES
    (2, 102),
    (1, 104);

    CREATE TABLE IF NOT EXISTS `urun` (
    `id` int(8) NOT NULL AUTO_INCREMENT,
    `urun` varchar(50) NOT NULL,
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;

    INSERT INTO `urun` (`id`, `urun`) VALUES
    (1, ‘mouse’),
    (2, ‘klavye’),
    (3, ‘cpu’);

    bir sorgu ile 104 grubundaki ürünler hariç tüm ürünlerin gelmesini istiyorum. örnekte cpu içingrup belirlenmemiş, onun da null gelmesi gerekli.

    şu şekilde getirebiliyorum;
    SELECT * FROM grup RIGHT JOIN urun ON urunid = id
    WHERE ( grup !=104 OR grup IS NULL)

    ama, yukarıda verdiğiniz “left join between” örneğindeki gibi uygularsam cpu kaydı gelmiyor.

    SELECT * FROM grup RIGHT JOIN urun ON urunid = id and grup!=104 gibi.

    Reply
  9. DURSUN
    May 2 2013

    SELECT u.* , s.satis_miktar
    FROM firmam.urun AS u
    LEFT JOIN firmam.satis AS s ON u.urun_id = s.urun_id
    AND s.satis_tarih BETWEEN ‘2010-12-01 00:00:00’ AND ‘2010-12-01 23:59:59’
    WHERE 1

    Bu sorgu örneği için teşekkurler. and kısmından sonraki kuşula benzer bir koşulu where altına yazıyordum istediğim bilgiler eksik geliyordu.

    Gerçekten güzel bir anlatım olmuş.

    Reply
  10. umut
    Jun 10 2013

    $sqql=”SELECT I.* , E.* FROM motor AS I LEFT JOIN motor_ek AS E ON I.Idd=E.Idd WHERE I.sts=2″; gibi bir sorgunun sonuçlarında Idd sütunu sonuçlarda dönmüyor hem Idd sütununu birleştirmede kullanıp hem dönen sonuçlarda görüntülemenin yolu yokmu. Bu arada çalışmalarınız için teşekkürler

    Reply
  11. Emir
    Aug 6 2013

    Merhaba,

    2 tablom var, uyeler ve yorumlar.
    uyeler: id, kulladi, kullsif, mail
    yorumlar: id, yorum, mail

    Ben yorum yapan kişinin mailinden uyeler tablosuna gidip o maile ait kulladi nı bulup onu yazdığı yorumun yanına yazdırmaya çalışıyorum.

    2 tane yorumu kayıtlı. Birini Emir Genç kullanıcısı yapmış diğerini Ahmet Genç kullanıcısı yapmış. yorumlar tablosunda bu şöyle kayıtlı:
    id: 1
    yorum: selam ben Emir.
    mail: [email protected]
    DİĞERİ
    id: 2
    yorum: Merhaba Emir
    mail: [email protected]

    Buradaki maillerden uyelere gidip isimleri seçtiğimde yalnıca tek ismi seçiyorve yazdırıyor. iki yorum alt alta ikisinde de Emre Genç ya da Ahmet Genç yazıyor. 2gündür kayboldum kodların içinde ve çıkamadım bir türlü, yardım rica ediyorum.

    Kullandığım kod:

    $sorgu = mysql_query(“SELECT kulladi FROM uyeler INNER JOIN yorumlar ON yorumlar.mail = uyeler.mail”);
    $sonuc = mysql_fetch_array($sorgu);
    echo “$sonuc[kulladi]”;

    Reply
  12. Talha ortas
    Oct 14 2013

    iyi çalışmalar benim bir sorum olacaktı. Ben bir blog sayfası yapıyorum blogların göründüğü yerde o blok hakkında kaçtane yorum yapılmış onu da göstercek Şu şekilde bir Sorgu Yaptım

    SELECT tbblog.*,Count(tbyorum.blogid) AS YORUMSAYISI FROM tbblog INNER JOIN tbyorum ON tbblog.id=tbyorum.blogid

    bu şekilde sorgu yaptım lakin bu sorguda hem tbyorum tablosunda blogid kolonuna bakmadan ne kadar yorum varsa o kadar gösteriyor hemde blog tablomdaki verilerden sadece birtanesini gösteriyor. İstediğimi nasıl yapabilirm? yardım ederseniz çok sevinirim

    Reply
  13. Taha
    Oct 19 2013

    Çok güzel ve faydalı bir makale olmuş teşekkürler hocam. Bide bu veritabanı şablonlarını neyle oluşturuyorsunuz onuda söylerseniz sevinirim.

    Reply
  14. Arda Balkan
    Apr 10 2014

    Dolu, gerçekten işe yarar bir yazı olmuş. Çok istifade ettim, teşekkürler.

    Reply

Sizin fikriniz nedir? Lütfen aşağıdaki formu kullanarak yorum yapın.

(gerekli)
(gerekli)