İçindekiler
Biçimlendirme/okunabilirlik
- Alanları ayırırken başta virgül kullanın
WHERE koşulunda kukla değer kullanın
- Uygun kod girintilemesi
- Karmaşık sorgular yazarken CTE kullanmayı düşünün
Yararlı özellikler
- Veri türü dönüştürmek için
:: operatörünü kullanın
- Anti join kullanın
- Pencere fonksiyonu filtrelemesinde
QUALIFY kullanın
GROUP BY için sütun konumu kullanılabilir
Kaçınılması gereken tuzaklar
NULL değerlerle NOT IN kullanırken dikkat edin
- Belirsizliği önlemek için hesaplanmış alan adlarını değiştirin
- Her sütunun hangi tabloya ait olduğunu belirtin
- Çalıştırma sırasını anlayın
- Koda yorum ekleyin
- Belgelerin tamamını okuyun
Biçimlendirme/okunabilirlik
Alanları ayırırken başta virgül kullanın
SELECT bölümünde alanları ayırırken başta virgül kullanarak yeni sütunları daha net ayırabilirsiniz
- Baştaki virgül, virgülün eksik olup olmadığını kolayca fark ettiren görsel bir ipucu sağlar
SELECT
employee_id,
employee_name,
job,
salary
FROM employees;
WHERE koşulunda kukla değer kullanın
WHERE koşulunda kukla değer kullanarak koşulları dinamik olarak ekleyip kaldırabilirsiniz
SELECT *
FROM employees
WHERE 1=1 -- kukla değer
AND job IN ('Clerk', 'Manager')
AND dept_no != 5;
Uygun kod girintilemesi
- Kodu girintileyerek okunabilirliği artırabilir ve ekip arkadaşlarınız ile gelecekteki kendiniz için kodu anlamayı kolaylaştırabilirsiniz
-- kötü örnek:
SELECT
timeslot_date,
timeslot_channel,
overnight_fta_share,
IFF(DATEDIFF(DAY, timeslot_date, CURRENT_DATE()) > 7,
LAG(overnight_fta_share, 1) OVER (PARTITION BY timeslot_date, timeslot_channel ORDER BY timeslot_activity),
NULL) AS C7_fta_share,
IFF(DATEDIFF(DAY, timeslot_date, CURRENT_DATE()) >= 29,
LAG(overnight_fta_share, 2) OVER (PARTITION BY timeslot_date, timeslot_channel ORDER BY timeslot_activity),
NULL) AS C28_fta_share
FROM timeslot_data;
-- iyi örnek:
SELECT
timeslot_date,
timeslot_channel,
overnight_fta_share,
IFF(DATEDIFF(DAY, timeslot_date, CURRENT_DATE()) > 7,
LAG(overnight_fta_share, 1) OVER (PARTITION BY timeslot_date, timeslot_channel ORDER BY timeslot_activity),
NULL) AS C7_fta_share,
IFF(DATEDIFF(DAY, timeslot_date, CURRENT_DATE()) >= 29,
LAG(overnight_fta_share, 2) OVER (PARTITION BY timeslot_date, timeslot_channel ORDER BY timeslot_activity),
NULL) AS C28_fta_share
FROM timeslot_data;
Karmaşık sorgular yazarken CTE kullanmayı düşünün
- İç içe inline view kullanmak yerine, ortak tablo ifadeleri (CTE) ile kodun okunabilirliğini ve düzenini artırabilirsiniz
-- inline view kullanımı:
SELECT
vhs.movie,
vhs.vhs_revenue,
cs.cinema_revenue
FROM
(SELECT
movie_id,
SUM(ticket_sales) AS cinema_revenue
FROM tickets
GROUP BY movie_id) AS cs
INNER JOIN
(SELECT
movie,
movie_id,
SUM(revenue) AS vhs_revenue
FROM blockbuster
GROUP BY movie, movie_id) AS vhs
ON cs.movie_id = vhs.movie_id;
-- CTE kullanımı:
WITH cinema_sales AS (
SELECT
movie_id,
SUM(ticket_sales) AS cinema_revenue
FROM tickets
GROUP BY movie_id
),
vhs_sales AS (
SELECT
movie,
movie_id,
SUM(revenue) AS vhs_revenue
FROM blockbuster
GROUP BY movie, movie_id
)
SELECT
vhs.movie,
vhs.vhs_revenue,
cs.cinema_revenue
FROM cinema_sales AS cs
INNER JOIN vhs_sales AS vhs
ON cs.movie_id = vhs.movie_id;
Yararlı özellikler
Veri türü dönüştürmek için :: operatörünü kullanın
- Bazı RDBMS'lerde
:: operatörüyle bir değeri başka bir veri türüne dönüştürebilirsiniz
SELECT CAST('5' AS INTEGER); -- CAST fonksiyonu kullanımı
SELECT '5'::INTEGER; -- :: sözdizimi kullanımı
Anti join kullanın
- Anti join, yalnızca tek bir tabloda bulunan satırları döndürmek gerektiğinde çok kullanışlıdır
- Alt sorgu da kullanılabilir, ancak genel olarak anti join daha hızlıdır
-- anti join:
SELECT
video_content.*
FROM video_content
LEFT JOIN archive
ON video_content.series_id = archive.series_id
WHERE archive.series_id IS NULL;
-- alt sorgu:
SELECT
*
FROM video_content
WHERE series_id NOT IN (SELECT DISTINCT series_id FROM archive);
-- ilişkili alt sorgu:
SELECT
*
FROM video_content
WHERE NOT EXISTS (
SELECT 1
FROM archive a
WHERE a.series_id = vc.series_id
);
-- EXCEPT:
SELECT series_id
FROM video_content
EXCEPT
SELECT series_id
FROM archive;
Pencere fonksiyonu filtrelemesinde QUALIFY kullanın
QUALIFY ile pencere fonksiyonlarının sonuçlarını filtreleyebilirsiniz
- Kod satırı sayısını azaltmada faydalıdır
-- QUALIFY kullanımı:
SELECT
product,
market,
SUM(revenue) AS market_revenue
FROM sales
GROUP BY product, market
QUALIFY DENSE_RANK() OVER (PARTITION BY product ORDER BY SUM(revenue) DESC) <= 10
ORDER BY product, market_revenue;
-- QUALIFY olmadan:
SELECT
product,
market,
market_revenue
FROM (
SELECT
product,
market,
SUM(revenue) AS market_revenue,
DENSE_RANK() OVER (PARTITION BY product ORDER BY SUM(revenue) DESC) AS market_rank
FROM sales
GROUP BY product, market
)
WHERE market_rank <= 10
ORDER BY product, market_revenue;
GROUP BY için sütun konumu kullanılabilir
- Sütun adı yerine sütun konumu kullanarak
GROUP BY veya ORDER BY yapabilirsiniz
- Geçici sorgular için kullanışlıdır, ancak prodüksiyon kodunda her zaman sütun adlarını referans almalısınız
SELECT
dept_no,
SUM(salary) AS dept_salary
FROM employees
GROUP BY 1 -- dept_no, SELECT bölümündeki ilk sütundur
ORDER BY 2 DESC;
Kaçınılması gereken tuzaklar
NULL değerlerle NOT IN kullanırken dikkat edin
NOT IN, NULL değerler varsa doğru çalışmaz
- Bunun yerine
NOT EXISTS kullanılmalıdır
INSERT INTO departments (id)
VALUES (1), (2), (NULL);
-- NULL değer yüzünden çalışmaz
SELECT *
FROM employees
WHERE department_id NOT IN (SELECT DISTINCT id FROM departments);
-- çözüm
SELECT *
FROM employees e
WHERE NOT EXISTS (
SELECT 1
FROM departments d
WHERE d.id = e.department_id
);
Belirsizliği önlemek için hesaplanmış alan adlarını değiştirin
- Hesaplanmış bir alanı mevcut bir sütun adıyla yeniden adlandırmak beklenmedik davranışlara yol açabilir
INSERT INTO products (product, revenue)
VALUES ('Shark', 100), ('Robot', 150), ('Alien', 90);
-- pencere fonksiyonu 'Robot' ürününü 1. sıraya yerleştirir
SELECT
product,
CASE product WHEN 'Robot' THEN 0 ELSE revenue END AS revenue,
RANK() OVER (ORDER BY revenue DESC)
FROM products;
Her sütunun hangi tabloya ait olduğunu belirtin
- Karmaşık sorgularda her sütunun hangi tabloya ait olduğunu belirtmek, sorunları izlemeyi kolaylaştırır
SELECT
vc.video_id,
vc.series_name,
metadata.season,
metadata.episode_number
FROM video_content AS vc
INNER JOIN video_metadata AS metadata
ON vc.video_id = metadata.video_id;
Çalıştırma sırasını anlayın
- SQL öğrenen biri için en önemli tavsiye, çalıştırma sırasını anlamaktır
- Çalıştırma sırasını anladığınızda sorgu yazma biçiminiz tamamen değişir
Koda yorum ekleyin
- Kod yazarken nedenini açıklayan yorumlar eklemelisiniz
- Ekip arkadaşlarınız ve gelecekteki kendiniz bunun için size teşekkür eder
SELECT
video_content.*
FROM video_content
LEFT JOIN archive -- yeni CMS arşiv video biçimini işleyemiyor
ON video_content.series_id = archive.series_id
WHERE archive.series_id IS NULL;
Belgelerin tamamını okuyun
- Belgeleri baştan sona okumak, beklenmedik sorunlardan kaçınmanıza yardımcı olabilir
- Belgeleri okumak yalnızca birkaç dakikanızı alır ve beklenmedik sorunları çözmenize yardımcı olur
-- belgeleri biraz daha okusaydınız NULL sorununu çözebilirdiniz
SELECT COALESCE(GREATEST(signup_date, consumption_date), signup_date, consumption_date);
-- GREATEST_IGNORE_NULLS fonksiyonu kullanılabilir
SELECT GREATEST_IGNORE_NULLS(signup_date, consumption_date);
GN⁺ özeti
- Bu yazı, SQL'i daha verimli ve okunabilir yazmak için çeşitli ipuçları ve püf noktaları sunuyor
- SQL'i yeni öğrenenler ya da deneyimli veri analistleri için çok sayıda yararlı bilgi içeriyor
- Özellikle karmaşık sorgular yazarken CTE kullanımı, anti join'den yararlanma ve
QUALIFY kullanımı pratikte büyük fayda sağlayacaktır
- SQL'in çalıştırma sırasını anlamak, koda yorum eklemek ve belgeleri dikkatle okuma alışkanlığı edinmek önemlidir
- Benzer işlevlere sahip diğer araçlar arasında PostgreSQL, MySQL ve Oracle bulunur
2 yorum
Bu gönderide baştaki virgüllerin hepsi sondaki virgül olarak yazılmış görünüyor. Orijinal metinde başta yer alıyorlar.
Hacker News görüşleri
DB sunucusunu iyi anlamak ve sorgu planını sık sık kontrol etme gerekliliği
EXISTS, çoğu durumdaIN'den daha hızlıdırNOT EXISTSveEXCEPT,NULLdeğerlerini işlerken farklı davranırUNION ALL,OR'dan daha hızlı olabilirJOIN'i ile filtreleme sırası zorlanabilirKarmaşık saklı prosedür işlemleri için ipuçları
Kod okunabilirliğiyle ilgili görüşler
SQL'de
FROM-first ve piping sözdiziminin kullanılması önerisiAnti Join ile ilgili ipuçları
EXISTSkullanımı önerilirSELECTifadesinde başta virgül kullanmanın avantajlarıMSSQL'de yorum kullanırken
--yerine/* */kullanılması önerilirWindow function kullanımının önerilmesi
WHEREkoşulunda1=1kullanımı üzerine tartışmaAI2sql tanıtımı