Birden çok satırı tek hücrede virgülle birleştirmek: farklı sistemlerde yöntem
Beceri rehberi

Birden çok satırı tek hücrede virgülle birleştirmek: farklı sistemlerde yöntem

Hazırlayan: Mindset Institute EditörlüğüGüncellendi: 5 dk okuma

Satırlardaki değerleri gruplayıp tek bir metinde ayraçla birleştirmek rapor ve dışa aktarımda sık gerekir. Farklı sistemlerdeki işlevi, sıralamayı ve kesilme tuzağını örneklerle görürsünüz.

Bir bakışta

  1. STRING_AGG, GROUP_CONCAT ve string_agg aynı işi görür: gruptaki satırların değerlerini tek metinde birleştirir. Ayraç, sıralama ve boş değer davranışı sistemden sisteme değişir.
  2. Bu bir toplama işlevidir; GROUP BY ile birlikte çalışır. SQL Server belgeleri, işlev SELECT listesindeki tek öğe değilse GROUP BY gerektiğini söyler.
  3. Sıralama yazılmazsa çıktı sırası garanti değildir. SQL Server'da WITHIN GROUP, MySQL ve PostgreSQL'de işlev içinde ORDER BY kullanılır.
  4. Uzun listeler sessizce kesilebilir. MySQL'de group_concat_max_len, SQL Server'da sonuç tipi sınırlayıcı olabilir.
  5. Birleştirilmiş metin rapor için iyidir, kalıcı veri modeli için değil. Metni sonradan bölmek, değerler ayraç içerdiğinde bozulur.

Satırları tek hücrede birleştirmek hangi sorunu çözer?

İlişkisel veritabanlarında bire çok ilişkiler satır satır akar: bir siparişin ürünleri, bir müşterinin etiketleri, bir makalenin yazarları ayrı satırlarda tutulur. Rapor ise çoğu zaman her varlık için tek satır ister: "Sipariş A: Elma, Armut, Kiraz". Satırları gruplayıp değerlerini tek bir metin hücresinde ayraçla birleştirmek bu ihtiyacı karşılar.

Bu işlem, satır içindeki birleştirmeden farklıdır. CONCAT gibi işlevler aynı satırdaki sütunları yan yana yazar; burada ise birden çok satırın aynı sütunu toplanır. Bu yüzden bir toplama (aggregate) işlevidir ve SUM ya da COUNT gibi GROUP BY ile birlikte çalışır.

Kullanım alanları gündelik: e-posta listesi çıkarmak (şehre göre müşteri adresleri), rapor tablosunda ürün listesini tek sütunda göstermek, kaynak sistemlere aktarılacak virgülle ayrılmış bir alan üretmek. Her sistemde işlevin adı ve ayrıntıları farklıdır; mantık aynıdır.

SQL Server'da STRING_AGG

SQL Server'da bu iş STRING_AGG işleviyle yapılır. Birleştirilecek ifade ve ayraç değerlerini alır. Microsoft belgelerine göre ayraç yalnızca değerlerin arasına konur, sonda görünmez. İşlev SQL Server'ın görece yeni sürümlerinde bulunur; eski sürümlerde yoktur.

SELECT s.siparis_kodu, STRING_AGG(u.urun_adi, ', ') AS urunler FROM dbo.Siparis AS s JOIN dbo.SiparisKalemi AS k ON k.siparis_id = s.siparis_id JOIN dbo.Urun AS u ON u.urun_id = k.urun_id GROUP BY s.siparis_kodu;

Belgeler, STRING_AGG SELECT listesindeki tek öğe değilse GROUP BY yan tümcesinin gerektiğini vurgular. Birleşmiş metnin sırasını belirlemek için işlevden hemen sonra WITHIN GROUP (ORDER BY u.urun_adi) yazılır. Sıra belirtmezseniz hangi değerin önce geleceği garanti değildir.

Boş değerler (NULL) birleştirmeye girmez ve onlar için ayraç da eklenmez. Boş kalanları görünür kılmak istiyorsanız ifadeyi ISNULL ile sarmalayıp bir yer tutucu yazabilirsiniz. Bir ayrıntı daha: sonuç tipi girdi tipine bağlıdır ve sınırlı metin tiplerinde sonuç da sınırlı kalabilir; uzun listelerde ifadeyi önce NVARCHAR(MAX) tipine çevirmek kesilmeyi önler. Microsoft'un kendi örnekleri de bu çevirmeyi kullanır.

MySQL'de GROUP_CONCAT

MySQL tarafında karşılık GROUP_CONCAT işlevidir. Sözdizimi daha zengindir: tekrarları DISTINCT ile eler, ORDER BY ile sıralar, SEPARATOR ile ayracı seçer. Ayraç belirtilmezse MySQL virgül kullanır.

SELECT sehir, GROUP_CONCAT(DISTINCT ad ORDER BY ad SEPARATOR '; ') AS musteriler FROM musteri GROUP BY sehir;

MySQL belgelerine göre NULL değerler atlanır; gruptaki tüm değerler NULL ise sonuç NULL döner. En sık karşılaşılan sürpriz, sonucun group_concat_max_len ayarıyla kesilmesidir. Bu ayarın varsayılan değeri kısadır; uzun listeler sessizce kırpılır ve hata görmezsiniz. Beklenen çıktı uzunsa oturum için bu değeri yükseltmek gerekir. Belgeler, değeri tahmini çıktı büyüklüğüne göre ayarlamayı, aşırı büyük bir değerin performansı bozabileceğini ve bellek sorununa yol açabileceğini söyler.

Bu işlevin SQL Server'dan farkı, DISTINCT ve ORDER BY'ın işlevin içine yazılmasıdır; SQL Server'da sıralama ayrı bir WITHIN GROUP bölümünden gelir.

PostgreSQL'de string_agg

PostgreSQL'de işlevin adı string_agg'dir ve bir değer ve bir ayraç alır. Sıralama, MySQL'e benzer biçimde işlevin içine yazılır:

SELECT sehir, string_agg(ad, ', ' ORDER BY ad) AS musteriler FROM musteri GROUP BY sehir;

PostgreSQL belgelerine göre NULL değerler birleştirmeye girmez; hiç satır seçilmediğinde ise boş metin değil NULL döner. Raporda boş görünmesini istiyorsanız sonucu coalesce ile sarmalayın. Girdi sırası varsayılan olarak belirsizdir; çıktının her çalıştırmada aynı çıkmasını istiyorsanız ORDER BY yazmak zorundasınız. Belgeler, sıralı bir alt sorguya güvenmenin birleştirme ya da başka işlem sıralamayı bozduğunda yanıltıcı olabileceğini de belirtir.

Aynı veriyi metin yerine liste olarak taşımak istiyorsanız array_agg bir seçenektir: değerleri bir dizide toplar ve NULL değerleri korur. Sonuç raporu okuyan insana değil, başka bir sorguya ya da uygulamaya gidiyorsa dizi, ayraçlı metinden daha güvenli bir taşıyıcıdır.

Sistemler arası farklar bir bakışta

Aynı sorguyu bir sistemden diğerine taşırken işlev adı kadar önemli olan davranış farklarıdır: sıralamanın nerede yazıldığı, boş değerlerin akıbeti ve sonucun uzunluk sınırı. Bunları yanlış varsaymak, taşınan sorguda sessiz veri kaybı demektir.

Pratik bir kural: yeni bir sisteme geçtiğinizde ilk iş, küçük bir deneme tablosuyla boş değer, tekrar eden değer ve uzun liste durumlarını denemektir. Beklediğiniz çıktıyı küçük örnekte görmeden gerçek tabloya geçmeyin.

Şekil 1

Aynı işi yapan işlevler sıralama, boş değer ve uzunlukta ayrışır

SQL ServerMySQLPostgreSQL
İşlev adıSTRING_AGGGROUP_CONCATstring_agg
AyraçAyraç bağımsız değişkeniSEPARATOR ile, varsayılan virgülAyraç bağımsız değişkeni
SıralamaWITHIN GROUP (ORDER BY ...)İşlevin içinde ORDER BYİşlevin içinde ORDER BY
Boş değerlerAtlanırAtlanırAtlanır
Uzunluk dikkatiSonuç tipi girdi tipine bağlıgroup_concat_max_len ile kesilirMetin tipinde döner
Kaynak: Kaynak: Microsoft Learn STRING_AGG, MySQL aggregate functions ve PostgreSQL aggregate functions belgeleri.Mindset Institute

Örnek senaryo: şehre göre müşteri e-posta listesi

Bir kurumsal satış ekibi, her şehirdeki müşterilere toplu bilgilendirme göndermek istiyor. Müşteri tablosunda her müşteri tek satırdır; şehir sütunu tekrar eder. İstenen çıktı, her şehir için tek satırda noktalı virgülle ayrılmış e-posta adresleridir.

Çözüm adımları şöyledir. Önce hangi satırların dahil edileceğini WHERE ile belirleyin, örneğin yalnızca aktif müşteriler. Sonra şehre göre GROUP BY yapın. Adresleri tercih ettiğiniz sistemin işleviyle birleştirin ve ayracı e-posta istemcisinin beklediği biçimde seçin. Boş e-posta alanlarının zaten dışarıda kaldığını, ama tamamen boş bir şehrin NULL sonuç döndürebileceğini unutmayın.

Sonuç birkaç şehirde çok uzunsa kesilme riski vardır. SQL Server'da ifadeyi NVARCHAR(MAX) tipine çevirmek, MySQL'de group_concat_max_len değerini artırmak bu riski ortadan kaldırır. Sonra çıktıdan rastgele bir şehir seçip adresleri tek tek saymak gibi bir elle doğrulama yapın; bu, kırpmayı fark etmenin en hızlı yoludur.

Sık yapılan hatalar ve nereden başlanır?

Görülen hatalar şunlardır: • GROUP BY'ı unutmak; işlev tek başına SELECT listesinde değilse sorgu hata verir. • Sıralama yazmadan kararlı çıktı beklemek; aynı sorgu farklı çalıştırmalarda farklı sırada dönebilir. • Değerlerin içinde ayraç karakteri bulunması; virgülle birleştirilmiş bir listeyi sonradan bölmek, adı "Ankara, Merkez" gibi virgül içeren bir değerde bozulur. • Birleştirilmiş metni veritabanında kalıcı olarak saklamak; bu, aynı bilgiyi tabloda satırlara bölmenin yerini tutmaz, çünkü o metni sorgulamak zorlaşır. • MySQL'de kırpılmayı fark etmemek.

Öğrenme sırası olarak önce SELECT, GROUP BY ve JOIN, ardından diğer toplama işlevleri gelmelidir. Mindset kataloğunda SQL ile Programlama Eğitimi, Toplama ve Gruplama modülüyle SUM, AVG, sayma ve gruplama temelini; Hesaplamalar modülüyle de metin birleştirme ve takma adları işler. Bu temeller oturduktan sonra STRING_AGG ya da muadili, rapor hazırlayan analist ve geliştiricinin günlük araç kutusuna girer.

İlgili Mindset programı

SQL ile Programlama Eğitimi

Sık sorulanlar

Sık sorulan sorular

STRING_AGG hangi SQL Server sürümlerinde çalışır?

Microsoft belgelerine göre STRING_AGG SQL Server'ın görece yeni sürümlerinde, Azure SQL Database ve Azure SQL Managed Instance gibi ilgili hizmetlerde kullanılabilir. Daha eski bir sürümdeyseniz işlev bulunmaz ve başka bir yöntem gerekir. Sürümünüzü SELECT @@VERSION ile öğrenebilirsiniz.

Birleştirilmiş metindeki değerleri alfabetik sıralamak için ne yapmalıyım?

SQL Server'da işlevden sonra WITHIN GROUP (ORDER BY sütun) yazarsınız. MySQL'de GROUP_CONCAT içine ORDER BY eklersiniz. PostgreSQL'de string_agg içine ORDER BY yazılır. Sıralama belirtmezseniz çıktı sırası garanti edilmez ve aynı sorgu farklı çalıştırmalarda farklı dizilimle dönebilir.

Tekrar eden değerleri birleştirmeden nasıl çıkarırım?

MySQL'de GROUP_CONCAT içinde DISTINCT kullanabilirsiniz. Diğer sistemlerde yaygın yöntem, önce tekrarları bir alt sorgu ya da CTE içinde SELECT DISTINCT ile elemek, sonra dışarıda birleştirmektir. Böylece davranış sistemler arasında aynı kalır ve taşıma sırasında sürpriz yaşamazsınız.

Birleştirilmiş sonuç neden yarıda kesiliyor?

MySQL'de sonuç group_concat_max_len ayarında durdurulur ve varsayılan sınır kısadır. SQL Server'da ise sınırlı metin tipinde gelen ifade sınırlı tipte sonuç verebilir; ifadeyi NVARCHAR(MAX) tipine çevirmek çözer. Bu durumlarda hata mesajı gelmeyebilir, bu yüzden uzun listelerde çıktıyı mutlaka kontrol edin.

Birleştirilmiş listeyi tekrar satırlara nasıl bölerim?

Her sistemin metni bölen bir işlevi ya da tablo döndüren bir karşılığı vardır; yöntem sürüme göre değişir. Daha önemlisi, değerler ayraç karakterini içerebiliyorsa bölme güvenilmez olur. Böyle bir ihtiyaç sürekliyse listeyi metinde değil, ilişkili ayrı satırlarda saklamak çok daha sağlam bir tasarımdır.

SQL STRING_AGG ve GROUP_CONCAT ile Satır Birleştirme