{"id":164,"date":"2019-09-30T22:20:20","date_gmt":"2019-09-30T19:20:20","guid":{"rendered":"http:\/\/www.potansif.com\/?p=164"},"modified":"2019-10-01T17:35:49","modified_gmt":"2019-10-01T14:35:49","slug":"sql-server-group_concat-ve-listagg-simulasyonu","status":"publish","type":"post","link":"http:\/\/www.potansif.com\/?p=164","title":{"rendered":"SQL Server : GROUP_CONCAT ve LISTAGG Sim\u00fclasyonu"},"content":{"rendered":"<p>Zaman zaman, birden \u00e7ok sat\u0131r\u0131n konusu olan baz\u0131 verileri tek h\u00fccrede g\u00f6stermek istedi\u011fimiz durumlar olabiliyor, ( \u00d6rne\u011fin, bir tabloda ge\u00e7en alanlar\u0131n adlar\u0131n\u0131 hemen yan\u0131ndaki s\u00fctunda virg\u00fcllerle ayr\u0131lm\u0131\u015f \u015fekilde g\u00f6rmek gibi )<br \/>\n<!--more--><br \/>\nMySQL&#8217;de bunun i\u00e7in harika bir komut var, tam da bu i\u015fi yap\u0131yor GROUP_CONCAT, ayn\u0131 \u015fekilde Oracle ve DB2&#8217;de de ayn\u0131 i\u015fi yapan LISTAGG fonksiyonu var fakat SQL Server&#8217;de bu i\u015fi yapman\u0131n do\u011frudan bir yolu yok, yani bir fonksiyona indirgenmi\u015f haz\u0131r bir \u00e7\u00f6z\u00fcm bulunmuyor. Bir bak\u0131ma haz\u0131r bir \u00e7\u00f6z\u00fcm\u00fcn olmamas\u0131 bizler i\u00e7in bir esneklik olarak da g\u00f6r\u00fclebilir, zira insan\u0131n ufkunu a\u00e7an k\u0131s\u0131m da tam olarak buras\u0131 \u00e7\u00fcnk\u00fc \u00f6n\u00fcn\u00fczde sizi engelleyecek bir durum yok, dolay\u0131s\u0131yla her\u015feyi denememeniz i\u00e7in hi\u00e7 bir neden g\u00f6remiyorum.<\/p>\n<p>( Ba\u015flamadan \u00f6nce \u00f6rneklerimizi bir tablo de\u011fi\u015fkeni \u00fczerinde g\u00f6sterece\u011fiz ve temp tablolar kullanarak diskinizi yormayaca\u011f\u0131z, b\u00f6ylece SQL Server&#8217;da gereksiz ve sonradan silmek isteyece\u011finiz t\u00fcrden \u00e7\u00f6p tablolar\u0131n olu\u015fmas\u0131na neden olmayaca\u011f\u0131z, bu sayfadaki kodlar\u0131 belle\u015fte \u00e7al\u0131\u015faca\u011f\u0131, i\u015fin i\u00e7ine disk girmeyece\u011fi i\u00e7in do\u011frudan kopyala-yap\u0131\u015ft\u0131r y\u00f6ntemiyle deneyebilirsiniz. )<\/p>\n<p>\u015eimdiki makalemizde bu i\u015flevselli\u011fi sorgular\u0131m\u0131zda nas\u0131l sa\u011flayabiliriz ve bunu hangi farkl\u0131 yollarla ger\u00e7ekle\u015ftirebiliriz onu irdeleyece\u011fiz.<\/p>\n<p>Deneysel verilerimizi bir tablo de\u011fi\u015fkeni olu\u015fturarak temelimizi atm\u0131\u015f olal\u0131m;<\/p>\n<pre><code>DECLARE &nbsp; @VERI &nbsp; &nbsp;TABLE\r\n &nbsp; &nbsp; &nbsp; &nbsp;( ID &nbsp; &nbsp; &nbsp; INT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IDENTITY(1,1)\r\n &nbsp; &nbsp; &nbsp; &nbsp;, Ad &nbsp; &nbsp; &nbsp; VARCHAR(20)\r\n &nbsp; &nbsp; &nbsp; &nbsp;, Soyad &nbsp; &nbsp;VARCHAR(20)\r\n &nbsp; &nbsp; &nbsp; &nbsp;);\r\n\r\nINSERT INTO @VERI (Soyad, Ad) VALUES ('Kurt', 'ali'), ('kurt', 'veli'), ('KURT', 'nuri'), ('ARSLAN', 'ali'), ('ARSLAN', 'hamdi'), ('ARSLAN', 'vecidi'), ('ARSLAN', 'G\u00f6ksel'), ('Kaplan', 'muhammet'), ('Kaplan', 'Ali'), ('Kaplan', '\u015eahin'), ('Kaplan', 'Aslan');\r\n\r\nSELECT &nbsp;ID, Ad, Soyad FROM @VERI;<\/code><\/pre>\n<p>\u015e\u00f6yle bir tablo elde etmi\u015f olduk<\/p>\n<pre><code>ID &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Ad &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Soyad\r\n----------- -------------------- --------------------\r\n1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ali &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Kurt\r\n2 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; veli &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; kurt\r\n3 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nuri &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; KURT\r\n4 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ali &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ARSLAN\r\n5 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; hamdi &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ARSLAN\r\n6 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; vecidi &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ARSLAN\r\n7 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; G\u00f6ksel &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ARSLAN\r\n8 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; muhammet &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Kaplan\r\n9 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Ali &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Kaplan\r\n10 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\u015eahin &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Kaplan\r\n11 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Aslan &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Kaplan\r\n\r\n(11 row(s) affected)<\/code><\/pre>\n<p>bu \u00f6rnekteki amac\u0131m\u0131z ayn\u0131 soyad\u0131na sahip olan ki\u015fileri soyad\u0131na g\u00f6re gruplay\u0131p isimlerini virg\u00fcl ile ayr\u0131lm\u0131\u015f bir \u015fekilde tek bir s\u00fctunda g\u00f6stermek olacak. Yani sonu\u00e7 olarak a\u015fa\u011f\u0131daki gibi bir liste elde etmemiz gerekiyor;<\/p>\n<pre><code>Soyad &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Ailedekiler\r\n-------------------- ---------------------------------\r\nARSLAN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ali, G\u00f6ksel, hamdi, vecidi\r\nKaplan &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Ali, Aslan, muhammet, \u015eahin\r\nKurt &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ali, nuri, veli\r\n\r\n(3 row(s) affected)<\/code><\/pre>\n<p>A\u015fa\u011f\u0131daki gibi bir kod kullanarak bu amaca ula\u015fabiliriz, fakat bu kod SQL Server&#8217;in veritaban\u0131 motoru a\u00e7\u0131s\u0131ndan \u00e7ok yorucudur, yani gereksiz fazladan i\u015fler yapar, \u00f6rnek olmas\u0131 a\u00e7\u0131s\u0131ndan g\u00fczel fakat &#8220;kullan\u0131rm\u0131s\u0131n&#8221; dersen, kullanmam derim. Bu arada bu tekni\u011fin ad\u0131 &#8220;Recursive CTE&#8221; olarak bilinmektedir&#8230;<\/p>\n<pre><code>WITH\r\n&nbsp; SIRALI as (\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;SELECT Soyad\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; , Ad\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; , Siralama = ROW_NUMBER() OVER (PARTITION BY Soyad ORDER BY Ad) -- &nbsp;Bu noktada her bir sat\u0131ra kendi soyad\u0131 grubu i\u00e7inde bir s\u0131ra numaras\u0131 vermi\u015f oluyoruz\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;FROM &nbsp; @VERI --&gt; AS SIRALI anlam\u0131ndad\u0131r...\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; )\r\n, SONUC AS (\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;SELECT SIRALI.Soyad\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; , cast(SIRALI.Ad as varchar(max)) as [\u0130simler] \/* K\u00f6\u015feli parantezdeyken Arap\u00e7a alan adlar\u0131 bile kullanabilirsiniz *\/\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; , SIRALI.Siralama\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;FROM &nbsp; SIRALI &nbsp;--&gt; AS SONUC anlam\u0131ndad\u0131r...\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;WHERE &nbsp;SIRALI.Siralama = 1\r\n\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;UNION ALL\r\n\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;SELECT &nbsp; &nbsp; SIRALI.Soyad\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; , &nbsp; &nbsp; SONUC.[\u0130simler] + ', ' + SIRALI.Ad\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; , &nbsp; &nbsp; SIRALI.Siralama\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;FROM &nbsp; &nbsp; &nbsp; SIRALI&nbsp;\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;INNER JOIN SONUC ON &nbsp;SONUC.Soyad &nbsp; &nbsp; = SIRALI.Soyad\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; AND SIRALI.Siralama = SONUC.Siralama + 1\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;)\r\n&nbsp; &nbsp; &nbsp; &nbsp;\r\nSELECT &nbsp; &nbsp;Soyad, MAX([\u0130simler]) as Ailedekiler\r\nFROM &nbsp; &nbsp; &nbsp;SONUC\r\nGROUP BY &nbsp;Soyad&nbsp;\r\nORDER BY &nbsp;Soyad\r\nOPTION &nbsp; &nbsp;(MAXRECURSION 0);<\/code><\/pre>\n<p>Yukar\u0131da, pek de sevmedi\u011fim ama \u00f6rnek olmas\u0131 a\u00e7\u0131s\u0131ndan bulunsun niyetiyle yazd\u0131\u011f\u0131m \u00f6rnek kodu bir kenara b\u0131rak\u0131rsak ayn\u0131 i\u015flevselli\u011fi bir \u0130MLE\u00c7 kullanarak da sorgular\u0131m\u0131za kazand\u0131rabiliriz, fakat haliyle bu da olabildi\u011fince karma\u015f\u0131k bir sorgu olacakt\u0131r haliyle, ki karma\u015f\u0131kl\u0131\u011f\u0131 kimse sevmez&#8230;<\/p>\n<pre><code>DECLARE &nbsp; @VERI &nbsp; &nbsp;TABLE\r\n&nbsp; &nbsp; &nbsp; &nbsp; ( ID &nbsp; &nbsp; &nbsp; INT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IDENTITY(1,1)\r\n&nbsp; &nbsp; &nbsp; &nbsp; , Ad &nbsp; &nbsp; &nbsp; VARCHAR(MAX) --&gt; \u00d6nceki \u00f6rneklerde MAX yerine 20 bayt oldu\u011funu belirtmi\u015ftik, \u015fimdiki \u00f6rnekte bu alana ailedeki isimleri toplayaca\u011f\u0131m\u0131z i\u00e7in b\u00f6yle bir de\u011fi\u015fiklik yapt\u0131k...\r\n&nbsp; &nbsp; &nbsp; &nbsp; , Soyad &nbsp; &nbsp;VARCHAR(20)\r\n&nbsp; &nbsp; &nbsp; &nbsp; );\r\n\r\nINSERT INTO @VERI (Soyad, Ad) VALUES ('Kurt', 'ali'), ('kurt', 'veli'), ('KURT', 'nuri'), ('ARSLAN', 'ali'), ('ARSLAN', 'hamdi'), ('ARSLAN', 'vecidi'), ('ARSLAN', 'G\u00f6ksel'), ('Kaplan', 'muhammet'), ('Kaplan', 'Ali'), ('Kaplan', '\u015eahin'), ('Kaplan', 'Aslan');\r\n\r\nDECLARE @Soyad &nbsp; &nbsp; &nbsp; &nbsp;VARCHAR(MAX)\r\n&nbsp; &nbsp; &nbsp; , @Ad &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; VARCHAR(MAX)\r\n&nbsp; &nbsp; &nbsp; , @Ailedekiler &nbsp;VARCHAR(MAX)\r\n&nbsp; &nbsp; &nbsp; ;\r\n&nbsp;\r\nDECLARE imlec CURSOR LOCAL FAST_FORWARD\r\nFOR &nbsp; &nbsp; SELECT &nbsp; &nbsp;Soyad, Ad&nbsp;\r\n&nbsp; &nbsp; &nbsp; &nbsp; FROM &nbsp; &nbsp; &nbsp;@VERI\r\n&nbsp; &nbsp; &nbsp; &nbsp; ORDER BY &nbsp;Soyad, Ad\r\n&nbsp; &nbsp; &nbsp; &nbsp; ;\r\n&nbsp;\r\nOPEN imlec;\r\n&nbsp;\r\nFETCH imlec INTO @Soyad, @Ad;\r\n&nbsp;\r\nWHILE @@FETCH_STATUS = 0 BEGIN\r\n&nbsp; &nbsp; &nbsp; UPDATE &nbsp;@VERI\r\n&nbsp; &nbsp; &nbsp; SET &nbsp; &nbsp; Ad = Ad + ', ' + @Ad\r\n&nbsp; &nbsp; &nbsp; WHERE &nbsp; Soyad = @Soyad\r\n&nbsp; &nbsp; &nbsp; ;\r\n&nbsp;\r\n&nbsp; &nbsp; &nbsp; FETCH imlec\r\n&nbsp; &nbsp; &nbsp; INTO &nbsp;@Soyad, @Ad;\r\nEND\r\n&nbsp;\r\nCLOSE imlec;\r\nDEALLOCATE imlec;\r\n&nbsp;\r\nSELECT &nbsp; &nbsp;Soyad, MAX(Ad) as Ailedekiler\r\nFROM &nbsp; &nbsp; &nbsp;@VERI\r\nGROUP BY &nbsp;Soyad\r\nORDER BY &nbsp;Soyad;<\/code><\/pre>\n<p>\u0130mle\u00e7 kullanmak mecbur olmad\u0131\u011f\u0131n\u0131z s\u00fcrece ka\u00e7man\u0131z \/ ka\u00e7\u0131nman\u0131z gereken ekstrem bir durumdur, veritaban\u0131 motoruna sat\u0131r baz\u0131nda y\u00fck bindirir ve sonu\u00e7 almak b\u00f6yle k\u0131sa veri y\u0131\u011f\u0131nlar\u0131 i\u00e7in dert olmasa bile binlerce verinin oldu\u011fu bir tabloda kelimenin tam anlam\u0131yla sizi s\u00fcr\u00fcnd\u00fcr\u00fcr. M\u00fcmk\u00fcnse uzak durum (ama y\u00f6ntemi bilin&#8230;)<\/p>\n<p>Bunun d\u0131\u015f\u0131nda \u00f6rnekleri biraz daha radikalle\u015ftirip bu i\u015f i\u00e7in UPDATE komutunu kullanabilir ve Ailedekileri ayr\u0131 bir s\u00fctuna hesaplatarak yazabiliriz, \u00e7al\u0131\u015ft\u0131\u011f\u0131m\u0131z tablo bir cari hesap ekstresi olsayd\u0131 kesinlikle bu y\u00f6ntemi \u00f6nerirdim ama verileri inceleyen 3. g\u00f6zler bu durumu pek ho\u015f kar\u015f\u0131lamazd\u0131, yine de payla\u015fay\u0131m;<\/p>\n<p>QUIRKY UPDATE olarak isimlendirilen bu tekni\u011fi uygulamadan \u00f6nce tablo yap\u0131s\u0131nda fazladan bir alana daha ihtiyac\u0131m\u0131z olacak, tam kod \u015f\u00f6yle;<\/p>\n<pre><code>DECLARE &nbsp; @VERI &nbsp; &nbsp; &nbsp; TABLE\r\n&nbsp; &nbsp; &nbsp; &nbsp; ( ID &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;INT &nbsp; &nbsp; &nbsp; &nbsp; IDENTITY(1,1)\r\n&nbsp; &nbsp; &nbsp; &nbsp; , Ad &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;VARCHAR(20)\r\n&nbsp; &nbsp; &nbsp; &nbsp; , Soyad &nbsp; &nbsp; &nbsp; VARCHAR(20)\r\n&nbsp; &nbsp; &nbsp; &nbsp; , Ailedekiler VARCHAR(MAX)\r\n&nbsp; &nbsp; &nbsp; &nbsp; );\r\n\r\nINSERT INTO @VERI (Soyad, Ad) VALUES ('Kurt', 'ali'), ('kurt', 'veli'), ('KURT', 'nuri'), ('ARSLAN', 'ali'), ('ARSLAN', 'hamdi'), ('ARSLAN', 'vecidi'), ('ARSLAN', 'G\u00f6ksel'), ('Kaplan', 'muhammet'), ('Kaplan', 'Ali'), ('Kaplan', '\u015eahin'), ('Kaplan', 'Aslan');\r\n\r\nDECLARE @Soyad VARCHAR(20), @Ailedekiler VARCHAR(MAX);\r\n\r\nUPDATE &nbsp;@VERI\r\nSET &nbsp; &nbsp; @Ailedekiler = Ailedekiler = COALESCE( &nbsp;CASE COALESCE(@Soyad, '') WHEN Soyad THEN @Ailedekiler + ', ' + Ad ELSE Ad END, '')\r\n&nbsp; &nbsp; &nbsp; , @Soyad &nbsp; &nbsp; &nbsp; = Soyad\r\n&nbsp; &nbsp; &nbsp; &nbsp; ;\r\n&nbsp;\r\nSELECT &nbsp; &nbsp;Soyad\r\n&nbsp; &nbsp; &nbsp; &nbsp; , MAX(Ailedekiler) &nbsp;as Ailedekiler\r\nFROM &nbsp; &nbsp; &nbsp;@VERI\r\nGROUP BY &nbsp;Soyad\r\nORDER BY &nbsp;Soyad;<\/code><\/pre>\n<p>Benim daha \u00e7ok tercih etti\u011fim ve size \u00f6nerece\u011fim ise XML PATH y\u00f6ntemidir, bununla birlikte yaz\u0131n\u0131n devam\u0131nda CROSS APPLY tekni\u011fi de favorilerim aras\u0131nda&#8230;.<\/p>\n<pre><code>SELECT &nbsp;DISTINCT\r\n&nbsp; &nbsp; &nbsp; &nbsp; Soyad\r\n&nbsp; &nbsp; &nbsp; , STUFF ( ( SELECT &nbsp; &nbsp;', ' + AAA.Ad\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FROM &nbsp; &nbsp; &nbsp;@VERI &nbsp; &nbsp;as AAA\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; WHERE &nbsp; &nbsp; AAA.Soyad = SONUC.Soyad&nbsp;\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ORDER BY &nbsp;AAA.Ad &nbsp; ASC\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FOR XML PATH('')&nbsp;\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; )\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; , 1\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; , 2\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; , '') as Ailedekiler\r\nFROM &nbsp; &nbsp;@VERI as SONUC;<\/code><\/pre>\n<p>G\u00f6r\u00fcld\u00fc\u011f\u00fc gibi k\u0131sa, \u00f6z ve basit bir teknik olmas\u0131na mukabil buna (inline sql olmas\u0131na) ra\u011fmen &#8220;h\u0131zl\u0131d\u0131r&#8221;<\/p>\n<p>\u015eayet, SQL Server 2014 ve sonras\u0131n\u0131 kullan\u0131yorsan\u0131z CROSS APPLY t\u00fcm bunlar\u0131n hepsinden daha iyi bir se\u00e7enek olabilir, hem basit, hem h\u0131zl\u0131, hemde mant\u0131\u011f\u0131n\u0131 kurmak programc\u0131lar a\u00e7\u0131s\u0131ndan daha basittir, i\u015fte \u00f6rnek kodlar;<\/p>\n<pre><code>SELECT &nbsp;DISTINCT\r\n&nbsp; &nbsp; &nbsp; &nbsp;Soyad\r\n&nbsp; &nbsp; &nbsp;, STUFF(Sulaledekiler, 1, 2, '') as Ailedekiler\r\nFROM &nbsp; &nbsp;@VERI as SSS\r\nCROSS APPLY\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;( SELECT &nbsp; &nbsp;concat(', ', Ad)\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;FROM &nbsp; &nbsp; &nbsp;@VERI &nbsp; &nbsp;as AAA\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;WHERE &nbsp; &nbsp; AAA.Soyad = SSS.Soyad&nbsp;\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ORDER BY &nbsp;AAA.Ad &nbsp; ASC\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;FOR XML PATH('')&nbsp;\r\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;) as tmp (Sulaledekiler)\r\n;<\/code><\/pre>\n<p>Performans konusuna gelecek olursak , ben testlerimi SQL Server 2012 \u00fczerinde yapt\u0131m ve edindi\u011fim sonu\u00e7lar 20000 sat\u0131rl\u0131 bir tablo i\u00e7in milisaniye cinsinden \u015f\u00f6yle; (Makinan\u0131z\u0131n i\u015flemci g\u00fcc\u00fc ve h\u0131z\u0131 herkeste de\u011fi\u015fik oldu\u011fundan siz farkl\u0131 ama paralel sonu\u00e7lar elde edebilirsiniz)<\/p>\n<pre><code>CROSS APPLY &nbsp; &nbsp; &nbsp; &nbsp;96,77 ms\r\nXML Path &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 98,47 ms\r\nQUIRKLY Update &nbsp; &nbsp;267,72 ms\r\nRECURSIVE CTE &nbsp; &nbsp; 486,33 ms\r\nCURSOR &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2198,51 ms<\/code><\/pre>\n<h1>SONU\u00c7<\/h1>\n<ul>\n<li>E\u011fer SQL Server 2000 gibi \u00e7ok eski bir s\u00fcr\u00fcmde s\u0131k\u0131\u015f\u0131p kald\u0131ysan\u0131z muhtemelen bu i\u015f i\u00e7in her tabloya \u00f6zel olak \u00fczere bir scalar fonksiyon yazman\u0131z gerekecektir ki muhtemelen performans\u0131 yine de bir imle\u00e7 kullanmaktan daha iyi olacakt\u0131r.<\/li>\n<li>2005, 2008, 2012 gibi s\u00fcr\u00fcmlerden birini kullan\u0131yorsan\u0131z XML PATH y\u00f6ntemi en iyi \u00e7\u00f6z\u00fcm olarak \u00f6n\u00fcm\u00fczde duruyor. Yukar\u0131da de\u011finilmemekle birlikte bilinmeyen karakterle de u\u011fra\u015fmak zorunda kalabilirsiniz,<\/li>\n<li>Yine 2005 ve sonras\u0131 i\u00e7in e\u011fer XML PATH y\u00f6nteminde ge\u00e7ersiz karakter hatalar\u0131yla u\u011fra\u015fmak istemiyorsan\u0131z CROSS APPLY tekni\u011fini \u00f6neririm&#8230;<\/li>\n<\/ul>\n<h1>Merak edenler i\u00e7in<\/h1>\n<ul>\n<li>DB2 i\u00e7in \u015fu yaz\u0131y\u0131 &nbsp; &nbsp; &nbsp; &nbsp;= <a href=\"https:\/\/www.ibm.com\/support\/knowledgecenter\/en\/SS6NHC\/com.ibm.swg.im.dashdb.sql.ref.doc\/doc\/r0058709.html\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/www.ibm.com\/support\/knowledgecenter\/en\/SS6NHC\/com.ibm.swg.im.dashdb.sql.ref.doc\/doc\/r0058709.html<\/a><\/li>\n<li>Oracle i\u00e7in \u015funu &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= <a href=\"https:\/\/www.techonthenet.com\/oracle\/functions\/listagg.php ve https:\/\/docs.oracle.com\/cd\/E11882_01\/server.112\/e41084\/functions089.htm#SQLRF30030\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/www.techonthenet.com\/oracle\/functions\/listagg.php ve https:\/\/docs.oracle.com\/cd\/E11882_01\/server.112\/e41084\/functions089.htm#SQLRF30030<\/a><\/li>\n<li>MySQL i\u00e7in ise \u015fu sayfay\u0131 = <a href=\"https:\/\/dev.mysql.com\/doc\/refman\/5.7\/en\/group-by-functions.html#function_group-concat\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/dev.mysql.com\/doc\/refman\/5.7\/en\/group-by-functions.html#function_group-concat<\/a><\/li>\n<li>Postresql ini de \u015fu &nbsp; &nbsp; &nbsp; = <a href=\"https:\/\/coderwall.com\/p\/eyknwa\/postgres-group_concat\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/coderwall.com\/p\/eyknwa\/postgres-group_concat<\/a><\/li>\n<\/ul>\n<p>inceleyebilirsiniz&#8230; Di\u011ferlerini ara\u015ft\u0131rmak da sizin ev \u00f6deviniz olsun \ud83d\ude42<\/p>\n<p><b>SON NOT : SQL Server 2017 ile birlikte yeni fonksiyonlara sahip oluyoruz, bunlardan biri de bu makalenin konusunu kar\u015f\u0131layan&nbsp;STRING_AGG fonksiyonu&#8230;<\/b><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Zaman zaman, birden \u00e7ok sat\u0131r\u0131n konusu olan baz\u0131 verileri tek h\u00fccrede g\u00f6stermek istedi\u011fimiz durumlar olabiliyor, ( \u00d6rne\u011fin, bir tabloda ge\u00e7en alanlar\u0131n adlar\u0131n\u0131 hemen yan\u0131ndaki s\u00fctunda virg\u00fcllerle ayr\u0131lm\u0131\u015f \u015fekilde g\u00f6rmek gibi )<\/p>\n","protected":false},"author":1,"featured_media":268,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[22,23,7],"class_list":["post-164","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog","tag-group_concat","tag-listagg","tag-sql-server"],"_links":{"self":[{"href":"http:\/\/www.potansif.com\/index.php?rest_route=\/wp\/v2\/posts\/164","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.potansif.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.potansif.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.potansif.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.potansif.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=164"}],"version-history":[{"count":1,"href":"http:\/\/www.potansif.com\/index.php?rest_route=\/wp\/v2\/posts\/164\/revisions"}],"predecessor-version":[{"id":165,"href":"http:\/\/www.potansif.com\/index.php?rest_route=\/wp\/v2\/posts\/164\/revisions\/165"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/www.potansif.com\/index.php?rest_route=\/wp\/v2\/media\/268"}],"wp:attachment":[{"href":"http:\/\/www.potansif.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=164"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.potansif.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=164"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.potansif.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=164"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}