<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>SQL Server ASP.NET C# Kitabı &#187; Query Analyzer</title>
	<atom:link href="http://www.ahmetkaymaz.com/wp-seo-link-holder_akaymaz.php/category/query-analyzer/feed/?404;http://www.ahmetkaymaz.com:80/category/query-analyzer/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ahmetkaymaz.com</link>
	<description>SQL Server, C#, VB.NET, ASP.NET, AJAX ile ilgili örnek kitap ve ipuçları</description>
	<lastBuildDate>Tue, 20 Dec 2011 09:25:15 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>SQL Server Önceki Satırların Toplamı</title>
		<link>http://www.ahmetkaymaz.com/2010/01/18/sql-server-onceki-satirlarin-toplami/</link>
		<comments>http://www.ahmetkaymaz.com/2010/01/18/sql-server-onceki-satirlarin-toplami/#comments</comments>
		<pubDate>Mon, 18 Jan 2010 14:07:56 +0000</pubDate>
		<dc:creator>Ahmet Kaymaz</dc:creator>
				<category><![CDATA[Query Analyzer]]></category>

		<guid isPermaLink="false">http://www.ahmetkaymaz.com/?p=335</guid>
		<description><![CDATA[Özellikle bazı raporlarda veri satırlarının yanına kendinden önceki satılardaki bir alanın toplamını yazma ihtiyacı duyabiliyoruz. Aşağıdaki gibi Satis isimli bir tablo olduğunu düşünelim.

Bu tabloda her dönemin karşısında o döneme ait ciro bulunmaktadır. Bu tablodaki verilere dayalı olarak aşağıdaki gibi bir sonuç elde etmek istiyoruz.


Bu sonucu elde etmek için Satis tablosunu kendisiyle JOIN etmemiz gerekmektedir. Tabloları [...]]]></description>
			<content:encoded><![CDATA[<div class="google_plus_one"><g:plusone size="standard" count="true" url="http://www.ahmetkaymaz.com/2010/01/18/sql-server-onceki-satirlarin-toplami/"></g:plusone></div><p>Özellikle bazı raporlarda veri satırlarının yanına kendinden önceki satılardaki bir alanın toplamını yazma ihtiyacı duyabiliyoruz. Aşağıdaki gibi Satis isimli bir tablo olduğunu düşünelim.</p>
<p><img src="http://www.ahmetkaymaz.com/wp-content/uploads/SQL_Server_Onceki_Satirlari_Topla_2.jpg"></p>
<p>Bu tabloda her dönemin karşısında o döneme ait ciro bulunmaktadır. Bu tablodaki verilere dayalı olarak aşağıdaki gibi bir sonuç elde etmek istiyoruz.</p>
<p><img src="http://www.ahmetkaymaz.com/wp-content/uploads/SQL_Server_Onceki_Satirlari_Topla_3.jpg"><br />
<span id="more-335"></span><br />
Bu sonucu elde etmek için Satis tablosunu kendisiyle JOIN etmemiz gerekmektedir. Tabloları Donem alanı üzerinden ilişkilendirmeliyiz. Her satırın karşısına kendisinden önceki dönemleri getirerek gruplama yapıyoruz.</p>
<pre name="code" class="sql">SELECT a.Donem,ISNULL(SUM(b.Tutar),0) OncekiToplam
FROM Satis a LEFT JOIN Satis b ON a.Donem>b.Donem
GROUP BY  a.Donem</pre>
<p>Burada LEFT JOIN yapmamızın nedeni 201001 öncesinde kayıt olmadığı içindir. Her dönemin karşısına o dönemin tutarını da yazarsak kümülatif toplamı daha net görmüş oluruz.</p>
<pre name="code" class="sql">SELECT a.Donem,MAX(a.Tutar)DonemTutari,ISNULL(SUM(b.Tutar),0) OncekiToplam
FROM Satis a LEFT JOIN Satis b ON a.Donem>b.Donem
GROUP BY  a.Donem</pre>
<p><img src="http://www.ahmetkaymaz.com/wp-content/uploads/SQL_Server_Onceki_Satirlari_Topla_4.jpg"></p>
<p>Satis tablosunu aşağıdaki gibi biraz daha detaylandıralım. Hem mağaza kolonunu ekleyelim hem de bir döneme ait birden fazla satır olacak şeklinde düzenleme yapalım.</p>
<p><img src="http://www.ahmetkaymaz.com/wp-content/uploads/SQL_Server_Onceki_Satirlari_Topla_1.jpg"></p>
<p>Burada bir döneme ait birden fazla satır olduğu için tabloyu bu haliyle JOIN ettiğimizde önceki dönemlere ait mükerrer kayıtlar da toplanmış olacaktır. Bu yüzden tabloyu öncelikle Dönem alanına göre özetlemek lazım.</p>
<pre name="code" class="sql">SELECT a.Donem,MAX(a.Tutar)DonemTutari,ISNULL(SUM(b.Tutar),0) OncekiToplam FROM
	(SELECT Donem,SUM(Tutar)Tutar FROM Satis GROUP BY Donem) a
		LEFT JOIN
	(SELECT Donem,SUM(Tutar)Tutar FROM Satis GROUP BY Donem) b
		ON a.Donem>b.Donem
GROUP BY  a.Donem</pre>
<p>Bu sorgudaki <i>SELECT Donem,SUM(Tutar)Tutar FROM Satis GROUP BY Donem</i> iç sorguyu bir View olarak ta oluşturabiliriz. Böylece sorgumuz daha anlaşılır olacaktır.</p>
<p>Veya SQL Server 2005 ile birlikte gelen Common Table Expression deyim yapısını kullanabiliriz.</p>
<pre name="code" class="sql">WITH cteSatis AS
(
	SELECT Donem,SUM(Tutar)Tutar FROM Satis GROUP BY Donem
)

SELECT a.Donem,MAX(a.Tutar)DonemTutari,ISNULL(SUM(b.Tutar),0) OncekiToplam
FROM cteSatis a LEFT JOIN cteSatis b ON a.Donem>b.Donem
GROUP BY  a.Donem</pre>
 
<span class = "" style = "height: 25px;  float: left; "><iframe src="http://www.facebook.com/plugins/like.php?href=http://www.ahmetkaymaz.com/2010/01/18/sql-server-onceki-satirlarin-toplami/&layout=standard&send=false&show_faces=false&width=&action=like&colorscheme=light&font=" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:px; height:25px"></iframe></span>]]></content:encoded>
			<wfw:commentRss>http://www.ahmetkaymaz.com/2010/01/18/sql-server-onceki-satirlarin-toplami/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>SQL&#8217;de HTML Formatında Sorgu</title>
		<link>http://www.ahmetkaymaz.com/2008/03/28/sql-html-export/</link>
		<comments>http://www.ahmetkaymaz.com/2008/03/28/sql-html-export/#comments</comments>
		<pubDate>Fri, 28 Mar 2008 20:31:52 +0000</pubDate>
		<dc:creator>Ahmet Kaymaz</dc:creator>
				<category><![CDATA[Query Analyzer]]></category>

		<guid isPermaLink="false">http://www.ahmetkaymaz.com/?p=250</guid>
		<description><![CDATA[BCP programı, Import / Export Wizard, SQL Server 2000&#8242;deki Data Transformation Services (DTS) ve SQL Server 2005&#8242;teki SQL Server Integration Services araçlarını kullanarak SQL Server içerisinde html formatında data çekilebilir. Aslında SQL Server&#8217;de bu tür formatta verilerin çekilmesinin Reporting Services aracılığıyla yapılması daha mantıklıdır. Fakat bu yazıda Reporting Services&#8217;i kurmadan bir sorgunun sonucunu html biçiminde [...]]]></description>
			<content:encoded><![CDATA[<div class="google_plus_one"><g:plusone size="standard" count="true" url="http://www.ahmetkaymaz.com/2008/03/28/sql-html-export/"></g:plusone></div><p>BCP programı, Import / Export Wizard, SQL Server 2000&#8242;deki Data Transformation Services (DTS) ve SQL Server 2005&#8242;teki SQL Server Integration Services araçlarını kullanarak SQL Server içerisinde html formatında data çekilebilir. Aslında SQL Server&#8217;de bu tür formatta verilerin çekilmesinin Reporting Services aracılığıyla yapılması daha mantıklıdır. Fakat bu yazıda Reporting Services&#8217;i kurmadan bir sorgunun sonucunu html biçiminde nasıl dışarı veririz onu örneklendireceğiz.<span id="more-250"></span></p>
<p>HTML export işlemi için <b>master.dbo.sp_makewebtask</b> yordamı kullanılır. Çok sayıda parametreye sahip olan bu yordamın en çok kullanılan parametreleri sorgu ve sorgu sonucunun yazıldığı html sayfasının adresidir.</p>
<pre name="code" class="sql">sp_makewebtask [@outputfile =] 'outputfile',
	[@query =] 'query'
    [, [@fixedfont =] fixedfont]
    [, [@bold =] bold]
    [, [@italic =] italic]
    [, [@colheaders =] colheaders]
    [, [@lastupdated =] lastupdated]
    [, [@HTMLheader =] HTMLheader]
    [, [@username =] username]
    [, [@dbname =] dbname]
    [, [@templatefile =] 'templatefile']
    [, [@webpagetitle =] 'webpagetitle']
    [, [@resultstitle =] 'resultstitle']
    [
        [, [@URL =] 'URL', [@reftext =] 'reftext']
        | [, [@table_urls =] table_urls,
		[@url_query =] 'url_query']
    ]
    [, [@whentype =] whentype]
    [, [@targetdate =] targetdate]
    [, [@targettime =] targettime]
    [, [@dayflags =] dayflags]
    [, [@numunits =] numunits]
    [, [@unittype =] unittype]
    [, [@procname =] procname ]
    [, [@maketask =] maketask]
    [, [@rowcnt =] rowcnt]
    [, [@tabborder =] tabborder]
    [, [@singlerow =] singlerow]
    [, [@blobfmt =] blobfmt]
    [, [@nrowsperpage =] n]
    [, [@datachg =] table_column_list]
    [, [@charset =] characterset]
    [, [@codepage =] codepage]</pre>
<p>sp_makewebtask yordamının sunduğu kolaylıklardan biri de html tabanlı bir sayfayı şablon olarak kullanıyor olmasıdır. En basit haliyle bir sorgunun çıktısını aşağıdaki gibi html formatınta export edebiliriz.</p>
<pre name="code" class="sql">EXECUTE sp_makewebtask @outputfile = 'C:\Sonuc.html',
@query = 'SELECT * FROM Musteri', @dbname = 'Deneme'</pre>
<p>Sorgunun sonucunda oluşan C:\Sonuc.html sayfasınının içeriği şu şekilde olacaktır.</p>
<pre name="code" class="xml">
<H1>Query Results</H1>
<HR>
	<PRE><TT>Last updated: 2008-02-20 11:19:51.457</TT></pre><br />
	<P><br />
	<P><TABLE BORDER=1><br />
	<TR><TH ALIGN=LEFT>MusteriId</TH><br />
	<TH ALIGN=LEFT>AdSoyad</TH></TR><br />
	<TR><TD><TT>1</TT></TD><TD><TT>Cem Aktar</TT></TD></TR><br />
	<TR><TD><TT>2</TT></TD><TD><TT>Sena</TT></TD></TR><br />
	<TR><TD><TT>5</TT></TD><TD><TT>Metin Meriç</TT></TD></TR><br />
	</TABLE></pre>
<p><img src="http://www.ahmetkaymaz.com/wp-content/uploads/Web_Assistant_Wizard_2.jpg"></p>
<p>sp_makewebtask yordamının desteklediği code-page&#8217;leri listelemek <b>sp_enumcodepages</b> yordamı kullanılır.</p>
<p>Html şablon dosyasını oluştururken SQL Server&#8217;den gelen verilerin hangi aralıkla hangi hücrelere arasına yazılacağı ASP.NET&#8217;teki yazım biçimine benzer olarak <b>&lt;%begindetail%&gt;</b> ve <b>&lt;%enddetail%&gt;</b> etiketiyle belirnir. Bu iki etiket yazma işleminin yapılacağı alanın başlangıç ve bitişini belirtir. Bu alana herhangi bir yere datayı yazdırmak için <b>&lt;%insert_data_here%&gt;</b> ifadesi kullanılır. Aşağıdaki gibi bir şablon oluşturalım.</p>
<pre name="code" class="html">
<h1>Müşteri Listesi</h1>
<table>
<tr>
<th><b>Müşteri Kodu</b></th>
<th><b>Müşteri Adı-Soyadı</b></th>
</tr>

<%begindetail%>
<tr>
<td><%insert_data_here%></td>
<td><%insert_data_here%></td>
</tr>

<%enddetail%>
</table>
</pre>
<p>Bu dosyayı MusteriSablon.tpl olarak kayıt edip dosyanın konumunu sp_makewebtask yordamına @templatefile parametresiyle gönderelim.</p>
<pre name="code" class="sql">EXECUTE sp_makewebtask @outputfile = 'c:\MusteriListe.html',
	@query = 'SELECT MusteriId,AdSoyad FROM Musteri',
	@templatefile = 'c:\MusteriSablon.tpl',
	@dbname = 'Deneme',@codepage=1254</pre>
<p><img src="http://www.ahmetkaymaz.com/wp-content/uploads/Web_Assistant_Wizard_3.jpg"></p>
<p>Şablon dosyasını ve sorgumuzu XML formatında değiştirdiğimiz XML çıktı da elde etmiş oluruz. Html etiketlerinin bulunduğu şablon dosyasını şu şekilde düzenleyelim.</p>
<pre name="code" class="xml"><root>
	<%begindetail%>
		<%insert_data_here%>
	<%enddetail%>
</root></pre>
<p>Bilindiği gibi T-SQL içerisinde sorgunun sonucunu xml formatında üretmek için &#8220;FOR XML&#8221; eki kullanılır. Sorgumuzu da aşağıdaki gibi değiştirelim.</p>
<pre name="code" class="sql">EXECUTE sp_makewebtask @outputfile = 'c:\MusteriListe.html',
	@query = 'SELECT MusteriId,AdSoyad FROM Musteri for xml auto',
	@templatefile = 'c:\MusteriSablon.tpl',
	@dbname = 'Deneme',@codepage=1254</pre>
<p>Bu durumda aşağıdaki gibi bir çıktı elde etmiş oluruz.</p>
<pre name="code" class="xml"><root>
	<Musteri MusteriId="1" AdSoyad="Cem Aktar"/>
	<Musteri MusteriId="2" AdSoyad="Sena"/>
	<Musteri MusteriId="5" AdSoyad="Metin Meriç"/>
</root></pre>
<p>sp_makewebtask yordamının yaptığı için görsel olarak hazırlamanın en kolay yolu SQL Server 2000&#8242;de <b>The Web Assistant Wizard</b> aracını kullanmaktır. </p>
<p><img src="http://www.ahmetkaymaz.com/wp-content/uploads/Web_Assistant_Wizard_1.jpg"></p>
<p>Bu aracın güzel yanı gerekirse bu işlemi otomatiğe bağlamamızı sağlamasıdır. Oluşturacağı Job aracılığıyla gerek belli peryotlarda gerekse tablo üstünde değişiklik yapıldığı zaman html dosyasının oluşmasını sağlar.</p>
<p>SQL Server 2005&#8242;te The Web Assistant Wizard aracı bulunmamaktadır. Şimdilik sp_makewebtask yordamı 2005&#8242;te çalışıyor olsa da sonraki sürümlerde kaldırılacağı yazılmaktadır. sp_makewebtask yordamının kullanımı SQL Server 2005&#8242;te güvenlik nedeniyle default olarak kapalı durumdadır. &#8220;Microsoft.SQL Server 2005 » Configration Tools » SQL Server Surface Area Configuration&#8221; aracından &#8220;Enable Web Asistanst&#8221; özelliği aktif hale getirilebilir. 2005 ile birlikte bu yordam yerine Reporting Services aracının kullanılması tavsiye edilmektedir.</p>
<p>Bu yazıda Reporting Services aracının da nasıl kullanılacağını bir sonraki yazıda örneklendireceğiz.</p>
<p>Bununla birlikte SQL Server 2005&#8242;te T-SQL&#8217;de sorgunun XML formatında dönmesini sağlayan &#8220;FOR XML&#8221; deyimini PATH parametresiyle birlikte kullanarak bir html tablo oluşturabiliriz.</p>
<pre name="code" class="sql">DECLARE @TableHeader varchar(200)
DECLARE @TabloBody varchar(max)

-- HTML tablosunun üst kısmını düzenleyelim
SET @TableHeader = '&lt;table cellpadding="1" cellspacing="1" border="1">'
	+'&lt;tr>&lt;th><b>Müşteri Kodu</b>&lt;/th>&lt;th>&lt;b>Ad Soyad&lt;/b>&lt;/th>&lt;/tr>'

--Tablonun iç kısmını düzenleyelim
SET @TabloBody=''

SET @TabloBody=CAST(
		(SELECT CAST(MusteriId as varchar(5)) + '&lt;/td>&lt;td>'+
			RTRIM(AdSoyad) + '&lt;/td>&lt;td>'
		FROM Musteri FOR XML PATH ('tr'),type)
	as varchar(max))

SET @TabloBody = @TableHeader + REPLACE( REPLACE( @TabloBody, '&lt;', '<' ), '&gt;', '>' )+ '&lt;/table&gt;'

--Bundan sonra @TabloBody değişkenin değeri mail olarak ilgili kişilere atılabilir
</pre>
 
<span class = "" style = "height: 25px;  float: left; "><iframe src="http://www.facebook.com/plugins/like.php?href=http://www.ahmetkaymaz.com/2008/03/28/sql-html-export/&layout=standard&send=false&show_faces=false&width=&action=like&colorscheme=light&font=" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:px; height:25px"></iframe></span>]]></content:encoded>
			<wfw:commentRss>http://www.ahmetkaymaz.com/2008/03/28/sql-html-export/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Bir Kullanıcının Yetkilerini Başka Kullanıcıya Kopyalamak</title>
		<link>http://www.ahmetkaymaz.com/2008/03/27/bir-kullanicinin-yetkilerini-baska-kullaniciya-kopyalamak/</link>
		<comments>http://www.ahmetkaymaz.com/2008/03/27/bir-kullanicinin-yetkilerini-baska-kullaniciya-kopyalamak/#comments</comments>
		<pubDate>Thu, 27 Mar 2008 16:14:43 +0000</pubDate>
		<dc:creator>Ahmet Kaymaz</dc:creator>
				<category><![CDATA[Query Analyzer]]></category>

		<guid isPermaLink="false">http://www.ahmetkaymaz.com/?p=243</guid>
		<description><![CDATA[SQL Server&#8217;de bir kullanıcıya verdiğimiz yetkileri başka bir kullanıcıya nasıl kopyalayabiliriz. T-SQL&#8217;de bunu doğrudan yapabileceğimiz bir komut yapısı bulunmamaktadır. Her defasında her kullanıcı için GRANT ve DENY ifadelerini kullanarak manual olarak aynı yetkilerin verilmesi gerekir. Veya Management Studio veya Enterprise Manager üzerindeki Generate Script bölümü kullanılarak veritabanına ait script kodları oluşturulur. Orada ilgili kopyalama ve [...]]]></description>
			<content:encoded><![CDATA[<div class="google_plus_one"><g:plusone size="standard" count="true" url="http://www.ahmetkaymaz.com/2008/03/27/bir-kullanicinin-yetkilerini-baska-kullaniciya-kopyalamak/"></g:plusone></div><p>SQL Server&#8217;de bir kullanıcıya verdiğimiz yetkileri başka bir kullanıcıya nasıl kopyalayabiliriz. T-SQL&#8217;de bunu doğrudan yapabileceğimiz bir komut yapısı bulunmamaktadır. Her defasında her kullanıcı için GRANT ve DENY ifadelerini kullanarak manual olarak aynı yetkilerin verilmesi gerekir. Veya Management Studio veya Enterprise Manager üzerindeki Generate Script bölümü kullanılarak veritabanına ait script kodları oluşturulur. Orada ilgili kopyalama ve değiştirme işlemi yapılır. Bu yazıda nasıl bir script yazılarak bu işlemin daha kolay yapılacağını örneklendireceğiz. <span id="more-243"></span></p>
<p>Öncelikle Login1 ve Login2 isminde iki tane SQL Server bağlantı kullanıcısı tanımlayalım. </p>
<pre name="code" class="sql">CREATE LOGIN Login1 WITH PASSWORD = '123';
GO
CREATE LOGIN Login2 WITH PASSWORD = '123';</pre>
<p>Bu kullanıcıları Deneme veritabanına bağlanmaları için ilişkilendirelim yani Deneme veritabanı için user tanımlayacağız.</p>
<pre name="code" class="sql">CREATE USER [Kullanici1] FOR LOGIN [Login1]
GO
CREATE USER [Kullanici2] FOR LOGIN [Login2]</pre>
<p>Kullanici1 isimli kullanıcıyı Deneme veritabanındaki Musteri tablosunu SELECT edebilecek ama INSERT ve DELETE yapamayacak şekilde yetkilendirelim. Musteri tablosundaki MusteriId kolonunu SELECT etmesin sadece AdSoyad kolonunu SELECT edebilsin.</p>
<pre name="code" class="sql">DENY DELETE ON [dbo].[Musteri] TO [Kullanici1]
DENY INSERT ON [dbo].[Musteri] TO [Kullanici1]
DENY SELECT ON [dbo].[Musteri] ([MusteriId]) TO [Kullanici1]
GRANT SELECT ON [dbo].[Musteri] ([AdSoyad]) TO [Kullanici1] AS [dbo]</pre>
<p>Bu işlemi kontrol etmek için Login1 ile SQL Server&#8217;e bağlanıp Musteri tablosundan kayıt silelim. Bu durumda <i><font color="red">The DELETE permission was denied on the object &#8216;Musteri&#8217;, database &#8216;Deneme&#8217;, schema &#8216;dbo&#8217;.</font></i> hata mesajıyla karşılaşırız. Veya tablodaki tüm kolonları listelemek istediğimiz zaman <i><font color="red">The SELECT permission was denied on the column &#8216;MusteriId&#8217; of the object &#8216;Musteri&#8217;, database &#8216;Deneme&#8217;, schema &#8216;dbo&#8217;.</font></i> hata mesajı verilir.</p>
<p>SQL Server 2005&#8242;in güvenlikle ilgili sorgulanacak catalog view&#8217;leri şunlardır;<br />
<b>sys.objects :</b> Mevcut veritabanı içerisindeki table, view, stored procedure nesnelerini listeler.<br />
<b>sys.columns :</b> Table, view gibi nesnelerin kolonlarını listeler.<br />
<b>sys.database_role_members :</b> Veritabanı kullanıcısıyla veritanı rolleri arasındaki ilişkiyi listeler.<br />
<b>sys.database_permissions :</b> Kullanıcı ve rollere atanmış olan database seviyesindeki yetkileri listeler.<br />
<b>sys.database_principals :</b> Database kullanıcı ve rollerini listeler.</p>
<p>Bu katalogları kullanarak tüm yetkileri ilişkili oldukları nesnelerle aşağıdaki script aracılığıyla listeleyebiliriz.</p>
<pre name="code" class="sql">select   database_permissions.permission_name,
           coalesce(objects.type_desc,database_permissions.class_desc)
                           + case when objects.type_desc is not null and minor_id > 0 then '-COLUMN'
                                      else '' end as object_type,
           case database_permissions.class_desc
                  when 'SCHEMA' then schema_name(major_id)
                  when 'OBJECT_OR_COLUMN' then
                                  case when minor_id = 0 then object_name(major_id)
                                   else (select object_name(object_id) + '.'+ name
                                          from sys.columns
                                          where object_id = database_permissions.major_id
                                             and column_id = database_permissions.minor_id) end
                  else 'other' end as object_name,
           database_principals.name as database_principal,
           database_permissions.state_desc as grant_state
from    sys.database_permissions
               join sys.database_principals
                     on database_permissions.grantee_principal_id = database_principals.principal_id
               left join sys.objects
                     on objects.object_id = database_permissions.major_id
where database_permissions.major_id > 0
    and permission_name in ('SELECT','INSERT','UPDATE','DELETE')
order by object_name </pre>
<p><img src="http://www.ahmetkaymaz.com/wp-content/uploads/SQL_Permission_Table_1.jpg"></p>
<p>SQL Server 2000&#8242;de konuyla ilgili olarak syspermissions, sysprotects, sysobjects, sysusers, syscolumns katalog nesneleri kullanılmaktadır. </p>
<p>Aşağıdaki kodlar bir kullanıcıya ait yetkileri diğer kullanıcıya kopyalamak için ikinci kullanıcıya göre uyarlanmış scriptleri oluşturur.</p>
<pre name="code" class="sql">SET NOCOUNT ON

DECLARE	@EskiKullanici sysname, @YeniKullanici sysname

SET	@EskiKullanici = 'Kullanici1'
SET	@YeniKullanici = 'Kullanici2'

SELECT '--'+ QUOTENAME(DB_NAME()) +' veritabanını seç'
SELECT 'USE' + SPACE(1) + QUOTENAME(DB_NAME())

SELECT '--'+ QUOTENAME(@EskiKullanici) + ' kullanıcısının yetkileri '+
	QUOTENAME(@YeniKullanici) +'''ye kopyalanacak'

SELECT	'EXEC sp_addrolemember @rolename ='
	+ SPACE(1) + QUOTENAME(USER_NAME(rm.role_principal_id), '''')
	+ ', @membername =' + SPACE(1) + QUOTENAME(@YeniKullanici, '''') AS '--Rol yetkileri'
FROM	sys.database_role_members AS rm
WHERE	USER_NAME(rm.member_principal_id) = @EskiKullanici
ORDER BY rm.role_principal_id ASC

SELECT	CASE WHEN perm.state <> 'W' THEN perm.state_desc ELSE 'GRANT' END
	+ SPACE(1) + perm.permission_name + SPACE(1) + 'ON '
	+ QUOTENAME(USER_NAME(obj.schema_id)) + '.' + QUOTENAME(obj.name)
	+ CASE WHEN cl.column_id IS NULL THEN SPACE(0) ELSE '(' + QUOTENAME(cl.name) + ')' END
	+ SPACE(1) + 'TO' + SPACE(1) + QUOTENAME(@YeniKullanici) COLLATE database_default
	+ CASE WHEN perm.state <> 'W' THEN SPACE(0) ELSE SPACE(1) + 'WITH GRANT OPTION' END
	AS '--Nesne Seviyesindeki Yetkiler'
FROM	sys.database_permissions AS perm
	INNER JOIN
	sys.objects AS obj
	ON perm.major_id = obj.[object_id]
	INNER JOIN
	sys.database_principals AS usr
	ON perm.grantee_principal_id = usr.principal_id
	LEFT JOIN
	sys.columns AS cl
	ON cl.column_id = perm.minor_id AND cl.[object_id] = perm.major_id
WHERE	usr.name = @EskiKullanici
ORDER BY perm.permission_name ASC, perm.state_desc ASC

SELECT	CASE WHEN perm.state <> 'W' THEN perm.state_desc ELSE 'GRANT' END
	+ SPACE(1) + perm.permission_name + SPACE(1)
	+ SPACE(1) + 'TO' + SPACE(1) + QUOTENAME(@YeniKullanici) COLLATE database_default
	+ CASE WHEN perm.state <> 'W' THEN SPACE(0) ELSE SPACE(1)
	+ 'WITH GRANT OPTION' END AS '--Database Seviyesindeki Yetkiler'
FROM	sys.database_permissions AS perm
	INNER JOIN
	sys.database_principals AS usr
	ON perm.grantee_principal_id = usr.principal_id
WHERE	usr.name = @EskiKullanici
AND	perm.major_id = 0
ORDER BY perm.permission_name ASC, perm.state_desc ASC</pre>
<p>Bu script aşağıdaki gibi script yapısını oluşturur. </p>
<p><code>--[Deneme] veritabanını seç<br />
----------------------------<br />
USE [Deneme]</p>
<p>-----------------------------<br />
--[Kullanici1] kullanıcısının yetkileri [Kullanici2]'ye kopyalanacak</p>
<p>--Rol yetkileri<br />
-----------------------------</p>
<p>--Nesne Seviyesindeki Yetkiler<br />
-----------------------------<br />
DENY DELETE ON [dbo].[Musteri] TO [Kullanici2]<br />
DENY INSERT ON [dbo].[Musteri] TO [Kullanici2]<br />
DENY SELECT ON [dbo].[Musteri]([MusteriId]) TO [Kullanici2]<br />
GRANT SELECT ON [dbo].[Musteri]([AdSoyad]) TO [Kullanici2]</p>
<p>--Database Seviyesindeki Yetkiler<br />
-----------------------------<br />
GRANT CONNECT  TO [Kullanici2]</code></p>
<p>Bu script&#8217;i Query Analyzer&#8217;a kopyalayıp çalıştırmamız yeterlidir.</p>
<p>Şimdi tüm yetkileri listeleyecek olursak aşağıdaki gibi Kullanici2 de dahil edilmiş olur.</p>
<p><img src="http://www.ahmetkaymaz.com/wp-content/uploads/SQL_Permission_Table_2.jpg"></p>
<p><i>Kaynak : vyaskn.tripod.com</i></p>
 
<span class = "" style = "height: 25px;  float: left; "><iframe src="http://www.facebook.com/plugins/like.php?href=http://www.ahmetkaymaz.com/2008/03/27/bir-kullanicinin-yetkilerini-baska-kullaniciya-kopyalamak/&layout=standard&send=false&show_faces=false&width=&action=like&colorscheme=light&font=" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:px; height:25px"></iframe></span>]]></content:encoded>
			<wfw:commentRss>http://www.ahmetkaymaz.com/2008/03/27/bir-kullanicinin-yetkilerini-baska-kullaniciya-kopyalamak/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>XML Formatını Kullanarak Metni Bölmek (String Split)</title>
		<link>http://www.ahmetkaymaz.com/2008/03/21/xml-formatini-kullanarak-metni-bolmek-string-split/</link>
		<comments>http://www.ahmetkaymaz.com/2008/03/21/xml-formatini-kullanarak-metni-bolmek-string-split/#comments</comments>
		<pubDate>Fri, 21 Mar 2008 15:02:02 +0000</pubDate>
		<dc:creator>Ahmet Kaymaz</dc:creator>
				<category><![CDATA[Query Analyzer]]></category>

		<guid isPermaLink="false">http://www.ahmetkaymaz.com/?p=241</guid>
		<description><![CDATA[SQL Server üzerinde programlama yaparken metinleri ayrıştıran split fonksiyonunun T-SQL&#8217;de olmayışının eksikliğini hep hissetmişizdir. Bir metni bölmenin birçok yöntemi olsa da hepsinin mantığı döngü kurup metin içerisinde virgül gibi bir ayıraçın konumu bularak her virgül arasındaki değeri listelemektir. SQLTeam&#8217;da denk geldiğim aşağıdaki yöntemin daha hızlı olduğu ve pratik olduğunu düşünüyorum.
IF OBJECT_ID('dbo.Split') IS NOT NULL
  [...]]]></description>
			<content:encoded><![CDATA[<div class="google_plus_one"><g:plusone size="standard" count="true" url="http://www.ahmetkaymaz.com/2008/03/21/xml-formatini-kullanarak-metni-bolmek-string-split/"></g:plusone></div><p>SQL Server üzerinde programlama yaparken metinleri ayrıştıran split fonksiyonunun T-SQL&#8217;de olmayışının eksikliğini hep hissetmişizdir. Bir metni bölmenin birçok yöntemi olsa da hepsinin mantığı döngü kurup metin içerisinde virgül gibi bir ayıraçın konumu bularak her virgül arasındaki değeri listelemektir. SQLTeam&#8217;da denk geldiğim aşağıdaki yöntemin daha hızlı olduğu ve pratik olduğunu düşünüyorum.</p>
<pre name="code" class="sql">IF OBJECT_ID('dbo.Split') IS NOT NULL
    DROP FUNCTION dbo.Split

GO
CREATE FUNCTION dbo.Split(@data NVARCHAR(MAX), @delimiter NVARCHAR(5))
RETURNS @t TABLE (data NVARCHAR(max))
AS
BEGIN

    DECLARE @textXML XML;
    SELECT    @textXML = CAST('<d>' + REPLACE(@data, @delimiter, '</d><d>') + '</d>' AS XML);

    INSERT INTO @t(data)
    SELECT  T.split.value('.', 'nvarchar(max)') AS data
    FROM    @textXML.nodes('/D') T(split)

    RETURN
END
GO</pre>
<p>dbo şemasına altında oluşturulan bu fonksiyonu kullanalım.</p>
<pre name="code" class="sql">DECLARE @text NVARCHAR(max)
SELECT @text = 'C#, VB.NET, SQL Server, AJAX'

SELECT * FROM dbo.Split(@text, ',')</pre>
<p><code>C#<br />
 VB.NET<br />
 SQL Server<br />
 AJAX</code></p>
 
<span class = "" style = "height: 25px;  float: left; "><iframe src="http://www.facebook.com/plugins/like.php?href=http://www.ahmetkaymaz.com/2008/03/21/xml-formatini-kullanarak-metni-bolmek-string-split/&layout=standard&send=false&show_faces=false&width=&action=like&colorscheme=light&font=" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:px; height:25px"></iframe></span>]]></content:encoded>
			<wfw:commentRss>http://www.ahmetkaymaz.com/2008/03/21/xml-formatini-kullanarak-metni-bolmek-string-split/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQL Server&#8217;de Neden &#8220;Sayılar&#8221; Tablosuna İhtiyaç Duyarız</title>
		<link>http://www.ahmetkaymaz.com/2008/03/14/sql-server-sayilar-tablosu-string-split/</link>
		<comments>http://www.ahmetkaymaz.com/2008/03/14/sql-server-sayilar-tablosu-string-split/#comments</comments>
		<pubDate>Fri, 14 Mar 2008 14:43:36 +0000</pubDate>
		<dc:creator>Ahmet Kaymaz</dc:creator>
				<category><![CDATA[Query Analyzer]]></category>

		<guid isPermaLink="false">http://www.ahmetkaymaz.com/?p=240</guid>
		<description><![CDATA[SQL Server belli sayı aralığında işlem yapmak için genellikle while döngüsü kullanılır. Oysa elimizin altında ardışık sayıların bulunduğu bir tablo bulunursa her defasında while ile sözkonusu aralıktaki sayıları bulmaktansa basit Join işlemleriyle başı ve sonu verilmiş tarihsel, sayısal ve metinsel bir aralık oluşturulabilir. Bu yazıda böyle bir tablonun nasıl oluşturulacağı ve ne tür durumlarda kullanabileceğimizi [...]]]></description>
			<content:encoded><![CDATA[<div class="google_plus_one"><g:plusone size="standard" count="true" url="http://www.ahmetkaymaz.com/2008/03/14/sql-server-sayilar-tablosu-string-split/"></g:plusone></div><p>SQL Server belli sayı aralığında işlem yapmak için genellikle while döngüsü kullanılır. Oysa elimizin altında ardışık sayıların bulunduğu bir tablo bulunursa her defasında while ile sözkonusu aralıktaki sayıları bulmaktansa basit Join işlemleriyle başı ve sonu verilmiş tarihsel, sayısal ve metinsel bir aralık oluşturulabilir. Bu yazıda böyle bir tablonun nasıl oluşturulacağı ve ne tür durumlarda kullanabileceğimizi örneklendireceğiz. Bu çalışmanın T-SQL ile ilgili iyi bir egzersiz olacağını düşünüyorum. <span id="more-240"></span></p>
<p>T-SQL aracılığıyla X ve Y aralığında sayıların bulunduğu bir tablo oluşturmanın bir çok yöntemi vardır. Bu yöntemlerin başında hiç şüphesiz while döngüsünü kullanmaktır. Öncelikle Sayilar isminde bir tablo oluşturalım.</p>
<pre name="code" class="sql">CREATE TABLE Sayilar
	(Sayi INT NOT NULL PRIMARY KEY CLUSTERED);</pre>
<p>Bu tabloda Sayi isminde tek bir kolon var. Bu kolon otomatik artan sayı özelliğine sahiptir yani tabloya eklenecek her satır için Sayi kolonuna yeni ardışık bir rakam eklenecektir. Şimdi While ile bu tabloya 1000&#8242;e kadar kayıt ekleyelim.</p>
<pre name="code" class="sql">DECLARE @x INT;
SET @x = 1;
WHILE @x <= 1000
BEGIN
    INSERT INTO Sayilar VALUES (@x);
    SELECT @x = @x + 1;
END</pre>
<p>Bu işlemden sonra Sayilar tablosuna 1'den 1000'e kadar sayılar eklenir. </p>
<p><img src="http://www.ahmetkaymaz.com/wp-content/uploads/Sayilar_Tablosu_1.jpg"></p>
<p>Böyle bir tablo oluşturmanın 2. yöntemi çok sayıda kayıt içeren bir tablodan 1000 kayıt okunur IDENTITY fonksiyonu kullanılarak her kayıt için sayısal bir değer üretilir ve bu liste Sayilar ismindeki tabloya insert edilir.</p>
<pre name="code" class="sql">IDENTITY (data_type [ , seed , increment ] ) AS column_name</pre>
<p>IDENTITY fonksiyonu ancak INTO ile birlikte kullanılabildiği için Sayilar tablosunun daha önce oluşturulmamış olması gerekir.</p>
<pre name="code" class="sql">-- Sayilar tablosunu silelim
DROP TABLE Sayilar;
GO
--İçerisinde çok kayıt bulunan Musteri tablosundan 1000 kayıt okuyoruz
--Sıralı sayısal liste 1'den başlayıp 1'er 1'er ilerlesin
SELECT TOP 1000 IDENTITY(int,1,1) AS Sayi
INTO Sayilar
FROM Musteri
GO
-- Tablo için bir primary key oluşturalım
ALTER TABLE Sayilar
ADD CONSTRAINT PK_Sayilar PRIMARY KEY CLUSTERED (Sayi);</pre>
<p>Bu sorgulara yakın olarak aşağıdaki gibi de Sayilar tablosu oluşturulabilir.</p>
<pre name="code" class="sql">CREATE TABLE Sayilar
(
	Sayi smallint IDENTITY(1, 1) PRIMARY KEY
)
GO

WHILE 1 = 1
BEGIN
	INSERT INTO Sayilar DEFAULT VALUES

	IF @@IDENTITY = 1000
	BEGIN
		BREAK
	END
END</pre>
<p>SQL Server 2005 ile birlikte gelmiş olan <b>ROW_NUMBER</b> fonksiyonunu da kullanarak ardışık rakamlar elde edebiliriz. Bir sıralama fonksiyonu (ranking function) olan ROW_NUMBER, parametre olarak aldığı kriterlere uygun kayıtları sıralı olarak numaralandırır. Çok kaydı olan bir tablodan 1000 kayıt olup bunları ardışıl olarak numaralandırabiliriz. Bunun için elimizde büyük bir tablo yoksa SQL Server'in standart katalog tablosu olan sysobjects tablosunu kendisiyle çapraz join ederek çok kayıtlı bir liste elde edebiliriz.</p>
<pre name="code" class="sql">SELECT TOP 1000 ROW_NUMBER() OVER(order by T1.name) as Sayi
 from sysobjects T1 cross join sysobjects T2</pre>
<p>Başka bir yöntem olarak SQL Server 2005'te Common Table Expressions (CTE) yapısını kullanmaktır. Bilindiği gibi CTE sayesinde recursion (öz-yinelemeli) işlemler basitçe yapılabilmektedir. Buradaki mantık sayısal bir değişken tanımlayıp bu değişkeni 1 artıran sorguyu rekürsif olarak çağırmaktır.</p>
<pre name="code" class="sql">WITH SayilarCTE(x)
AS(
	SELECT x = 1
	UNION ALL
	SELECT x = x + 1 FROM SayilarCTE WHERE x < 1000
)
INSERT Sayilar
SELECT x FROM SayilarCTE ORDER BY x
OPTION (maxrecursion 1000)</pre>
<p>Mevcut yöntemler içeriside CTE yönteminin en hızlı seçenek olduğunu söyleyebiliriz. Peki bu tablo hangi sorgularda yardımcı araç olarak kullanabiliriz. </p>
<p><b><u>Virgüllü değerleri çözmek (split işlemi)</u></b></p>
<p>İlk örnek olarak virgül veya başka karakterle birbirinden ayrılmış metinsel ifadeleri (CSV -comma seperated values) çözmek için bu tablodan yararlanabiliriz. Eğer ifadenin içerisinde sadece sayısal değerler varsa yapacağımız şey Sayilar tablosundaki sayilari CHARINDEX aracılığıyla sözkonusu metin içerisinde aramaktır. CHARINDEX fonksiyonu iki parametre alıp ilk parametredeki değerin ikinci parametre içerisindeki konumunu döndürür. Eğer ilk değer, ikinci değer içerisinde geçmiyorsa geriye 0 döndürür. Aşağıdaki örnekte 14,8,1,5,3,2 ifadesinin çözülmesi sağlanmıştır.</p>
<pre name="code" class="sql">DECLARE @metin VARCHAR(255)
SET @metin = '14,8,1,5,3,2' 

SELECT Sayi
    FROM Sayilar
    WHERE CHARINDEX
    (
        ','+CONVERT(VARCHAR(12),Sayi)+',',
        ','+@metin+','
    ) > 0
    ORDER BY Sayi
</pre>
<p><code>1<br />
2<br />
3<br />
5<br />
8<br />
14</code></p>
<p>Eğer çözülecek ifade içerisinde sadece sayısal değil metinsel (string) ifadeler de varsa aşağıdaki gibi düzenleme yapılır. Virgüllü ifadeye geçmeden önce bir kelimedeki harfleri listeleyen bir sorgu yazalım.</p>
<pre name="code" class="sql">DECLARE @Kelime varchar(50)
SET @Kelime='İstanbul'

SELECT  Harf
FROM
(
	SELECT TOP 100 PERCENT SUBSTRING(@Kelime, Sayi, 1) AS Harf
	FROM Sayilar
	--Sayilar tablosunda ifadenin uzunluğu kadar satır okuyacağız
	WHERE Sayi <= LEN(@Kelime)
	ORDER BY Harf
) AS Tb</pre>
<p><code>İ<br />
s<br />
t<br />
a<br />
n<br />
b<br />
u<br />
l</code></p>
<p>Bu ifadedeki tekil harfleri listlemek için içteki sorguya aşağıdaki DISTINCT eklemek yeterli olacaktır.</p>
<pre name="code" class="sql">DECLARE @Kelime varchar(50)
SET @Kelime='Ankara'

SELECT  Harf
FROM
(
	SELECT DISTINCT TOP 100 PERCENT SUBSTRING(@Kelime, Sayi, 1) AS Harf
	FROM Sayilar
	--Sayilar tablosunda ifadenin uzunluğu kadar satır okuyacağız
	WHERE Sayi <= LEN(@Kelime)
	ORDER BY Harf
) AS Tb</pre>
<p><code>A<br />
k<br />
n<br />
r</code></p>
<p>Herhangi bir metin içerisindeki sayıları bulalım.</p>
<pre name="code" class="sql">DECLARE @Kelime varchar(50), @Sayi varchar(50)
SET @Kelime='İstanbul  29 Mayıs 1453''te fethedildi.'
SET @Sayi=''

SELECT  @Sayi = @Sayi +  Harf
FROM
(
	SELECT SUBSTRING(@Kelime, Sayi, 1) AS Harf
	FROM Sayilar
	--Sayilar tablosunda ifadenin uzunluğu kadar satır okuyacağız
	WHERE Sayi <= LEN(@Kelime)
) AS Tb
WHERE Harf LIKE '[0-9]' 

SELECT 'Sonuç : '+ @Sayi</pre>
<p><code>Sonuç : 291453</code></p>
<p>Şimdi virgüllü bir ifadeyi çözümleyelim.</p>
<pre name="code" class="sql">DECLARE @metin VARCHAR(255)
SET @metin = 'İstanbul,Ankara,İzmir,Gaziantep' 

SELECT SUBSTRING
    (
		',' + @metin + ',',
        Sayi + 1,
    CHARINDEX
        (
            ',',
            ',' + @metin + ',',
            Sayi + 1
        ) - Sayi - 1
    )
    FROM Sayilar
    WHERE Sayi >= 1
        AND Sayi < LEN(',' + @metin + ',') - 1
        AND SUBSTRING(',' + @metin + ',', Sayi, 1) = ','
    ORDER BY Sayi </pre>
<p><code>İstanbul<br />
Ankara<br />
İzmir<br />
Gaziantep</code></p>
<p><b><u>Silinmiş identity değerleri bulmak.</u></b></p>
<p>Sayilar tablosunu kullanabileceğimiz ikinci örnek ise IDENTITY türündeki bir kolonda silinmiş değerleri bulmaktır. Bilindiği gibi bu tür kolonlarda bir kayıt silindiği zaman silinen kayda ait ID bilgisi bir daha başka bir satıra verilmez. Böylece silme işlemlerinden sonra identity zincirinde kopukluklar olacaktır. Aşağıdaki örnekte tabloda 8 kayıt oluşturulmuş ve ardından listeden 2 kayıt silinmişti. Alt kısımdaki sorgu silinen bu 2 kaydın identity bilgisini listeleyecektir.</p>
<pre name="code" class="sql">CREATE TABLE OrnekTablo
(
    SatirId INT IDENTITY(1,1)
)
--Örnek tabloya kayıtlar ekleyelim.
INSERT OrnekTablo DEFAULT VALUES
INSERT OrnekTablo DEFAULT VALUES
INSERT OrnekTablo DEFAULT VALUES
INSERT OrnekTablo DEFAULT VALUES
INSERT OrnekTablo DEFAULT VALUES
INSERT OrnekTablo DEFAULT VALUES
INSERT OrnekTablo DEFAULT VALUES
DELETE OrnekTablo WHERE SatirId = 3
INSERT OrnekTablo DEFAULT VALUES
DELETE OrnekTablo WHERE SatirId = 1
GO
SELECT Sayi
    FROM Sayilar
    WHERE Sayi NOT IN (SELECT SatirId FROM OrnekTablo)
    AND Sayi < (SELECT MAX(SatirId) FROM OrnekTablo)
    ORDER BY Sayi 

GO
--Örnek tabloyu silelim
DROP TABLE OrnekTablo </pre>
<p><code>1<br />
3</code></p>
<p><b><u>Belli aralıktaki tarihleri bulmak.</u></b></p>
<p>Üçüncü örnek olarak belli aralıktaki tarihleri listeleyeceğiz. Bunun için normalde while ile döngü kurmak gerekirdi. Burada while döngüsü kullanmak yerine Sayilar tablosunu referans alarak verilmiş olan ilk tarihten son tarihe varıncaya kadar tarihe gün sayısı eklenecektir. </p>
<pre name="code" class="sql">DECLARE @IlkTarih SMALLDATETIME, @SonTarih SMALLDATETIME
SET @IlkTarih = '20070101'
SET @SonTarih = '20070110' 

SELECT @IlkTarih + Sayi
    FROM Sayilar
    WHERE @IlkTarih + Sayi <= @SonTarih </pre>
<p><code>2007-01-02 00:00:00<br />
2007-01-03 00:00:00<br />
2007-01-04 00:00:00<br />
2007-01-05 00:00:00<br />
2007-01-06 00:00:00<br />
2007-01-07 00:00:00<br />
2007-01-08 00:00:00<br />
2007-01-09 00:00:00<br />
2007-01-10 00:00:00</code></p>
<p><i>Kaynak : http://www.aspfaq.com</i></p>
 
<span class = "" style = "height: 25px;  float: left; "><iframe src="http://www.facebook.com/plugins/like.php?href=http://www.ahmetkaymaz.com/2008/03/14/sql-server-sayilar-tablosu-string-split/&layout=standard&send=false&show_faces=false&width=&action=like&colorscheme=light&font=" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:px; height:25px"></iframe></span>]]></content:encoded>
			<wfw:commentRss>http://www.ahmetkaymaz.com/2008/03/14/sql-server-sayilar-tablosu-string-split/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQL&#8217;de Özet Tarih Tablosu / Date dimension table</title>
		<link>http://www.ahmetkaymaz.com/2008/02/27/sqlde-ozet-tarih-tablosu-date-dimension-table/</link>
		<comments>http://www.ahmetkaymaz.com/2008/02/27/sqlde-ozet-tarih-tablosu-date-dimension-table/#comments</comments>
		<pubDate>Wed, 27 Feb 2008 06:40:09 +0000</pubDate>
		<dc:creator>Ahmet Kaymaz</dc:creator>
				<category><![CDATA[Query Analyzer]]></category>

		<guid isPermaLink="false">http://www.ahmetkaymaz.com/?p=232</guid>
		<description><![CDATA[Bu blogda doğrudan yeni teknolojileri anlatmak yerine eski ve yeni teknolojileri gözetmeksizin günlük hayatta, projelerde ihtiyaç duyulan yöntemleri, ipuçlarını, konuları, örnekleri, yazılım geliştirme sürecinde dikkat edilmesi gereken konuları vermeye çalışıyoruz. Yazılım mühendisliğiyle ve C# veya VB.NET programlama dilleriyle ilgili detaylı konuları yakın zamanda çıkacak olan kitaplarımda vermeye çalıştım. Bu küçük yazıda da özellikle veri ambarı [...]]]></description>
			<content:encoded><![CDATA[<div class="google_plus_one"><g:plusone size="standard" count="true" url="http://www.ahmetkaymaz.com/2008/02/27/sqlde-ozet-tarih-tablosu-date-dimension-table/"></g:plusone></div><p>Bu blogda doğrudan yeni teknolojileri anlatmak yerine eski ve yeni teknolojileri gözetmeksizin günlük hayatta, projelerde ihtiyaç duyulan yöntemleri, ipuçlarını, konuları, örnekleri, yazılım geliştirme sürecinde dikkat edilmesi gereken konuları vermeye çalışıyoruz. Yazılım mühendisliğiyle ve C# veya VB.NET programlama dilleriyle ilgili detaylı konuları yakın zamanda çıkacak olan kitaplarımda vermeye çalıştım. Bu küçük yazıda da özellikle veri ambarı raporlama sistemlerinde işlerimizi kolaylaştıracak Tarih tablosunun içeriğini vereceğiz. &#8220;Date dimension table&#8221; olarak isimlendirilen bu tablo tüm data warehouse sistemlerinde ortak olup sistemin kullanım amacına uygun olarak farklı detaylar içerir. Belli tarih aralığının detaylarını içeren bu tablo çalışma anında tarihsel hesaplamaların neden olacağı performans ve zaman kaybını engeller. Bu tablo aynı zamanda OLTP uygulamalarında lookup olarak ta kullanılabilir.<br />
<span id="more-232"></span></p>
<p>Örnek verdiğimiz aşağıda tabloda bir tarihin, tarih formatı, hafta ve ay bilgisi, haftanın, ayın ve yılın kaçıncı günü olduğu, haftasonuna denk gelip gelmediği gibi bilgiler verilmektedir.</p>
<pre name="code" class="sql">CREATE TABLE L_Tarih(
	Bugun int NOT NULL, --YYYYMMDD formatında tarih. Tablonun primary key'i.
	FormatliBugun char(10) NULL,--DD.MM.YYYY formatında tarih
	GunAd char(10) NULL,
	AyAd char(10) NULL,
	TarihAd varchar(50) NULL,--'10 Aralık 2007 Pazartesi' gibi
	BuYil char(4) NULL,--Sene bilgisi
	BuAy char(6) NULL,--Yıl ve ay bilgisi. YYYYMM
	BuHafta char(6) NULL,--Yıl ve hafta bilgisi. YYYYWW
	Dun char(10) NULL,
	GecenHaftaBugun char(10) NULL,
	GecenAyBugun char(10) NULL,
	GecenYil char(4) NULL,
	GecenYilBugun char(10) NULL,
	GecenYilBuHafta char(6) NULL,
	GecenYilBuAy char(6) NULL,
	HaftaIlkGun char(10) NULL,--Bugünün bulunduğu haftanın başı
	HaftaSonGun char(10) NULL,--Bugünün bulunduğu haftanın sonu
	AyIlkGun char(10) NULL,
	AySonGun char(10) NULL,
	HaftaGunNo int NULL,--Haftanın kaçıncı günü
	AyGunNo int NULL,--Ayın kaçıncı günü
	YilGunNo int,--Yılın kaçıncı günü
	AyGunSayi int NULL,
	YilIlkGun char(10) NULL,
	YilSonGun char(10) NULL,
	HaftaSonu bit NULL--Haftasonu olup olmadığını belirtir
)</pre>
<p>Şeması bu şekilde olan tabloya aşağıdaki script&#8217;i çalıştırarak iki tarih aralığındaki tarih detaylarını yazdıralım.</p>
<pre name="code" class="sql">DECLARE @IlkTarih DATETIME
DECLARE @SonTarih DATETIME

SET @IlkTarih = '01-01-2007'
SET @SonTarih = '31-12-2008'

DECLARE @Bugun INT, @FormatliBugun CHAR(10), @GunAd CHAR(10), @AyAd CHAR(10),
	@TarihAd VARCHAR(50), @BuYil CHAR(4), @BuAy CHAR(6), @BuHafta CHAR(6),
	@Dun CHAR(10), @GecenHaftaBugun CHAR(10), @GecenAyBugun CHAR(10),
	@GecenYil CHAR(4), @GecenYilBugun CHAR(10),@GecenYilBuHafta CHAR(6),
	@GecenYilBuAy CHAR(6),@HaftaGunNo INT, @AyGunNo INT,@YilGunNo INT,
	@HaftaIlkGun CHAR(10), @HaftaSonGun CHAR(10),@AyGunSayi INT,
	@AyIlkGun CHAR(10), @AySonGun CHAR(10), @YilIlkGun CHAR(10),
	@YilSonGun CHAR(10), @HaftaSonu BIT

WHILE @IlkTarih <= @SonTarih
BEGIN
	SET @Bugun=CONVERT(VARCHAR(8), @IlkTarih, 112)
	SET @FormatliBugun=CONVERT(VARCHAR(10), @IlkTarih, 104)
	SET @GunAd=DATENAME(dw, @IlkTarih)
	SET @AyAd=DATENAME(mm, @IlkTarih)
	SET @TarihAd=CAST(DATEPART(dd, @IlkTarih) AS CHAR(2)) +' '+ DATENAME(mm, @IlkTarih) + ' '
			+ CAST(DATEPART(yy, @IlkTarih) AS CHAR(4))+' '+ @GunAd
	SET @BuYil=DATENAME(yy, @IlkTarih)
	SET @BuAy=LEFT(@Bugun,6)
	SET @BuHafta=CAST(DATEPART(ww, @IlkTarih) as CHAR(2))
	--Tek hane ise başına "0" ekleyelim
	SET @BuHafta=@BuYil+REPLICATE('0', 2 - LEN(@BuHafta))+@BuHafta
	SET @Dun= CONVERT(VARCHAR(8),DATEADD(dd,-1, @IlkTarih),112)
	SET @GecenHaftaBugun=CONVERT(VARCHAR(8),DATEADD(dd,-7, @IlkTarih),112)
	SET @GecenAyBugun=CONVERT(VARCHAR(8),DATEADD(mm,-1, @IlkTarih),112)
	SET @GecenYil=CONVERT(VARCHAR(8),DATEADD(yy,-1, @IlkTarih),112)
	SET @GecenYilBugun=CONVERT(VARCHAR(8),DATEADD(dd,-365, @IlkTarih),112)
	SET @GecenYilBuHafta=CAST(DATEPART(ww, @GecenYilBugun) as CHAR(2))
	--Tek hane ise başına "0" ekleyelim
	SET @GecenYilBuHafta=@GecenYil+REPLICATE('0', 2 - LEN(@GecenYilBuHafta))+@GecenYilBuHafta
	SET @GecenYilBuAy=LEFT(@GecenYilBugun,6)
	--Tarihin bulunduğu haftanın ilk günü
	SET @HaftaIlkGun=CONVERT(VARCHAR(8),DATEADD(dd,-(DATEPART(dw, @IlkTarih) - 1),@IlkTarih),112)
	--Tarihin bulunduğu haftanın son günü
	SET @HaftaSonGun=CONVERT(VARCHAR(8),DATEADD(dd,-(DATEPART(dw, @IlkTarih) - 7),@IlkTarih),112)
	--Ayın ilk günü
	SET @AyIlkGun=@BuAy+'01'
	--Ayın son günü
	SET @AySonGun=CONVERT(VARCHAR(8),DATEADD(d, -DAY(DATEADD(m,1,@IlkTarih)),DATEADD(m,1,@IlkTarih)),112)
	SET @YilIlkGun=@BuYil+'0101'
	SET @YilSonGun=@BuYil+'0131'
	--Ayın kaç gün olduğunu hesaplayalım
	SET @AyGunSayi=DAY(DATEADD(d, -DAY(DATEADD(m,1,@IlkTarih)),DATEADD(m,1,@IlkTarih)))
	--Tarihin haftanın kaçıncı günü olduğunu hesaplayalım
	SET @HaftaGunNo=DATEPART(dw , @IlkTarih)
	--Tarihin ayın kaçıncı günü olduğunu hesaplayalım
	SET @AyGunNo=DATEPART(day , @IlkTarih)
	--Tarihin yılın kaçıncı günü olduğunu hesaplayalım
	SET @YilGunNo=DATEPART(dy , @IlkTarih)

	--Tarihin haftasonu olup olmadığını bulalım
	SET @HaftaSonu= CASE WHEN @HaftaGunNo IN (6,7) THEN 1 ELSE 0 END

	--Elde ettiğimiz bilgileri lookup tablosuna aktaralım
	INSERT L_Tarih (Bugun, FormatliBugun, GunAd, AyAd, TarihAd,
			BuYil,BuAy,BuHafta,Dun,GecenHaftaBugun,GecenAyBugun,
			GecenYil,GecenYilBugun,GecenYilBuHafta,GecenYilBuAy,
			HaftaIlkGun,HaftaSonGun,AyIlkGun,AySonGun,HaftaGunNo,
			AyGunNo,YilGunNo,AyGunSayi,YilIlkGun,YilSonGun,HaftaSonu)
	VALUES(@Bugun, @FormatliBugun, @GunAd, @AyAd, @TarihAd,
			@BuYil,@BuAy,@BuHafta,@Dun,@GecenHaftaBugun,@GecenAyBugun,
			@GecenYil,@GecenYilBugun,@GecenYilBuHafta,@GecenYilBuAy,
			@HaftaIlkGun,@HaftaSonGun,@AyIlkGun,@AySonGun,@HaftaGunNo,
			@AyGunNo,@YilGunNo,@AyGunSayi,@YilIlkGun,@YilSonGun,@HaftaSonu)

	--Döngü içerisinde bir sonraki güne geçelim
	SET @IlkTarih = DATEADD(dd, 1, @IlkTarih)
END</pre>
<p>Bu scriptleri dili Türkçe olan bir kullanıcıyla çalıştırdığımızda tarih tablosu Türkçe formatına göre oluşturulur. L_Tarih tablosuna 2007 ve 2008 yıllarına ait tarih bilgileri eklenmiş olur.</p>
<p><img src="http://www.ahmetkaymaz.com/wp-content/uploads/Tarih_Lookup_Tablosu.jpg"></p>
<p>Bu tablo üzerinde bazı sorgular çalıştıralım. 2008 yılında hangi günden kaç adet bulunduğunu sorgulayalım.</p>
<pre name="code" class="sql">SELECT Max(HaftaGunNo) [Gün Numarası],GunAd [Gün Adı], COUNT(*) Adet
FROM L_Tarih WHERE BuYil = 2008
GROUP BY GunAd ORDER BY 1</pre>
<table>
<tr>
<td><b>Gün Numarası</b></td>
<td><b>Gün Adı</b></td>
<td><b>Adet</b></td>
</tr>
<tr>
<td>1</td>
<td>Pazartesi</td>
<td>52</td>
</tr>
<tr>
<td>2</td>
<td>Salı</td>
<td>53</td>
</tr>
<tr>
<td>3</td>
<td>Çarşamba</td>
<td>53</td>
</tr>
<tr>
<td>4</td>
<td>Perşembe</td>
<td>52</td>
</tr>
<tr>
<td>5</td>
<td>Cuma</td>
<td>52</td>
</tr>
<tr>
<td>6</td>
<td>Cumartesi</td>
<td>52</td>
</tr>
<tr>
<td>7</td>
<td>Pazar</td>
<td>52</td>
</tr>
</table>
<p>Görüldüğü gibi 2008 yılında 53 adet Salı ve Çarşamba günü bulunmaktadır. Aynı şekilde 2008 yılında ayların kaçar güne sahip olduğunu sorgulayalım.</p>
<pre name="code" class="sql">SELECT BuAy [Ay], Max(AyAd) [Ay Adı], COUNT(Bugun) [Gün Sayısı]
FROM L_Tarih WHERE BuYil = 2008
GROUP BY BuAy ORDER BY 1</pre>
<table>
<tr>
<td><b>Ay</b></td>
<td><b>Ay Adı</b></td>
<td><b>Gün Sayısı</b></td>
</tr>
<tr>
<td>200801</td>
<td>Ocak</td>
<td>31</td>
</tr>
<tr>
<td>200802</td>
<td>Şubat</td>
<td>29</td>
</tr>
<tr>
<td>200803</td>
<td>Mart</td>
<td>31</td>
</tr>
<tr>
<td>200804</td>
<td>Nisan</td>
<td>30</td>
</tr>
<tr>
<td>200805</td>
<td>Mayıs</td>
<td>31</td>
</tr>
<tr>
<td>200806</td>
<td>Haziran</td>
<td>30</td>
</tr>
<tr>
<td>200807</td>
<td>Temmuz</td>
<td>31</td>
</tr>
<tr>
<td>200808</td>
<td>Ağustos</td>
<td>31</td>
</tr>
<tr>
<td>200809</td>
<td>Eylül</td>
<td>30</td>
</tr>
<tr>
<td>200810</td>
<td>Ekim</td>
<td>31</td>
</tr>
<tr>
<td>200811</td>
<td>Kasım</td>
<td>30</td>
</tr>
<tr>
<td>200812</td>
<td>Aralık</td>
<td>31</td>
</tr>
</table>
<p>Bu tür tablolar OLAP uygulamalarında özetleme seviyeleri olarak kullanılır. Örneğin özellikle reel büyüme değerleri için haftalık, aylık, yıllık karşılaştırmalar herhangi bir tarih hesaplaması yapılmadan kolayca buradaki veriler kullanılabilir. Örneğin satış, sipatiş tablolarıyla JOIN edilerek farklı zaman dilimine göre satış veya sipariş analizleri yapılabilir.</p>
 
<span class = "" style = "height: 25px;  float: left; "><iframe src="http://www.facebook.com/plugins/like.php?href=http://www.ahmetkaymaz.com/2008/02/27/sqlde-ozet-tarih-tablosu-date-dimension-table/&layout=standard&send=false&show_faces=false&width=&action=like&colorscheme=light&font=" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:px; height:25px"></iframe></span>]]></content:encoded>
			<wfw:commentRss>http://www.ahmetkaymaz.com/2008/02/27/sqlde-ozet-tarih-tablosu-date-dimension-table/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Kolondaki Verileri Tek Satırda Göstermek(Concatenate İşlemi)</title>
		<link>http://www.ahmetkaymaz.com/2007/04/24/kolondaki-verileri-birlestirmekconcatenate-islemi/</link>
		<comments>http://www.ahmetkaymaz.com/2007/04/24/kolondaki-verileri-birlestirmekconcatenate-islemi/#comments</comments>
		<pubDate>Tue, 24 Apr 2007 21:28:58 +0000</pubDate>
		<dc:creator>Ahmet Kaymaz</dc:creator>
				<category><![CDATA[Query Analyzer]]></category>

		<guid isPermaLink="false">http://www.ahmetkaymaz.com/kolondaki-verileri-birlestirmekconcatenate-islemi/2007/04/24/</guid>
		<description><![CDATA[T-SQL&#8217;de iki string&#8217;i birleştirmek için CONCAT metodu kullanılır. Bazı durumlarda aynı satırdaki verileri değil alt altta durunda verileri birleştirmek isteyebiliriz. Bunun için klasik değer birleştirilme yöntemi kullanılır. Örneğin bir müşteriye ait ikinci bir tabloda row olarak duran birden fazla telefonunu, okuduğu gazeteleri, hobilerini okuyup tek bir satırda gösterme ihtiyacı duyabiliriz. Musteri ve MusteriTelefon tabloları olduğunu [...]]]></description>
			<content:encoded><![CDATA[<div class="google_plus_one"><g:plusone size="standard" count="true" url="http://www.ahmetkaymaz.com/2007/04/24/kolondaki-verileri-birlestirmekconcatenate-islemi/"></g:plusone></div><p>T-SQL&#8217;de iki string&#8217;i birleştirmek için CONCAT metodu kullanılır. Bazı durumlarda aynı satırdaki verileri değil alt altta durunda verileri birleştirmek isteyebiliriz. Bunun için klasik değer birleştirilme yöntemi kullanılır. Örneğin bir müşteriye ait ikinci bir tabloda row olarak duran birden fazla telefonunu, okuduğu gazeteleri, hobilerini okuyup tek bir satırda gösterme ihtiyacı duyabiliriz. Musteri ve MusteriTelefon tabloları olduğunu düşünelim.<i><br />Musteri<br />&#8212;&#8212;&#8212;&#8212;&#8211;<br />1    Ahmet Kaymaz<br />2    Mehmet Kaymaz<br /></i></p>
<p><i><br />MusteriTelefon<br />&#8212;&#8212;&#8212;&#8212;&#8211;<br />1	(0212)111<br />
1	(0533)111<br />
2	(0216)111<br />
2	(0542)111</i></p>
<p>İlk işlem olarak örneğin ID&#8217;si 1 olan Ahmet Kaymaz&#8217;ı telefonlarını birleştirerek getirelim. Bunun için tipik string birleştirmesi yapacağız.<span id="more-67"></span>
<pre name="code" class="sql">DECLARE @Telefonlar varchar(50)
SET @Telefonlar=''--Sonuç NULL olmasın diye

SELECT @Telefonlar = @Telefonlar + ','+ MT.Telefon
FROM MusteriTelefon MT WHERE MT.MusteriId=1

SELECT @Telefonlar</pre>
<p><code>,(0212)111 ,(0533)111</code> Bu ifade de @Telefonlar değişkenin ilk değeri NULL olduğu öncelikle boş değer vermek zorundayız. Çünkü T-SQL&#8217;de <i>&#8216;A&#8217;+NULL</i> ifadesi gibi NULL ile işleme giren ifadenin sonucu NULL olur. Aynı şekilde MusteriTelefon tablosunda NULL kayıt olsaydı sonuç yine NULL olacaktı. Bunları çözmek için <b>ISNULL()</b> metodu kullanılır. İki parametre alan bu metod, ilk değer NULL olduğu zaman ikinci parametredeki değeri döndürür.
<pre name="code" class="sql">DECLARE @Telefonlar varchar(50)
SET @Telefonlar=''

SELECT @Telefonlar = @Telefonlar + ISNULL(','+ MT.Telefon,'')
FROM MusteriTelefon MT WHERE MT.MusteriId=1

SELECT @Telefonlar</pre>
<p>Bu şekilde @Telefonlar değişkeninin her defasında NULL olup olmamasıyla uğraşmamak için T-SQL&#8217;in <b>COALESCE()</b> metodu önerilir. Bu metod, parametre olarak değerler listesini alarak bu değerler içerisinde NULL olmayan ilk kaydı döndürür. <i>SELECT COALESCE(NULL,NULL,&#8217;A',NULL,&#8217;B')</i> ifadesinin sonucu &#8220;A&#8221; olarak döner. Örnek queryi aşağıdaki gibi düzenleyelim.
<pre name="code" class="sql">DECLARE @Telefonlar varchar(50)

SELECT @Telefonlar = COALESCE(@Telefonlar + ',', '') + ISNULL(MT.Telefon,'')
FROM MusteriTelefon MT WHERE MT.MusteriId=1

SELECT @Telefonlar</pre>
<p>Her müşterinin telefonlarını bu şekilde listelemek için telefonları birleştiren bir fonksiyon hazırlamalıyız. Musteri tablosunu listelerken MusteriId&#8217;sini parametre alacak bu fonksiyonu da SELECT içerisinde çağırmalıyız.
<pre name="code" class="sql">CREATE FUNCTION dbo.GetTelefon
(
    @MusteriId int
)
RETURNS VARCHAR(50)
AS
BEGIN
    DECLARE @Telefonlar varchar(50)
    SELECT @Telefonlar = COALESCE(@Telefonlar + ',', '') + ISNULL(MT.Telefon,'')
	FROM MusteriTelefon MT WHERE MT.MusteriId=@MusteriId

    RETURN @Telefonlar
END </pre>
<p>Her müşteri için bu fonksiyonu çağıralım.
<pre name="code" class="sql">SELECT AdSoyad, dbo.GetTelefon(MusteriId) FROM Musteri</pre>
<p>Ahmet Kaymaz	(0212)111 ,(0533)111<br />
Mehmet Kaymaz	(0216)111 ,(0542)111</p>
<p>Bu yazıda asıl bahsetmek istediğim nokta, konuyla ilgili SQL Server 2005 ile birlikte gelmiş özelliklerdir. Bunların ilki <b>FOR XML  PATH</b> ifadesidir. Bu ifade, sorgulanan kolondaki kayıtları XML formatında listelerken nasıl bir prefix ve root yapısı kullanacağımızı, kolonu XML node olarak mı yoksa attribute olarak mı gösterebileceğimizi kolayca belirtmemize ve geri dönen kayıtları normal bir kolon gibi XPATH mantığıyla sorgulamamıza imkan tanır. Aşağıdaki örnek satırları inceleyelim.
<pre name="code" class="sql">--FOR XML PATH, parametresi kullanıldığı zaman node adı olarak "row" yazar.
--Herhangi bir kolon adı belirtilmemişse
SELECT 'C#' FOR XML PATH
--<row>C#</row>

--Kolon adı belirtilmişse
SELECT 'C#' [YeniNesilDil] FOR XML PATH
--<row><YeniNesilDil>C#</YeniNesilDil></row>

/*Kolon adı belirtilirken ön ekler kullanılabilir.
@ işareti, o kolonun attribute olarak yazılacağını
@ işareti yerine olmayıp "/"slash içeriyorsa o kolon için bir XML hiyerarşi oluşturulur
* wildcard karakteri, kolon adını gözardı eder
*/
SELECT 'C#' [@YeniNesilDil] FOR XML PATH
--<row YeniNesilDil="C#"/>

SELECT MusteriId [@MId],AdSoyad FROM Musteri FOR XML PATH
--<row MId="1"><AdSoyad>Ahmet Kaymaz</AdSoyad></row>

SELECT MusteriId [@MId],
AdSoyad "Musteri/Ad",Sehir "Musteri/Şehir" FROM Musteri FOR XML PATH
/*
<row MId="1">
	<Musteri>
		<Ad>Ali Korkmaz</Ad>
		<Şehir>İstanbul</Şehir>
	</Musteri>
</row>
*/

SELECT MusteriId [@MId],
AdSoyad "*",Sehir "*" FROM Musteri FOR XML PATH
/*
<row MId="1">
	Ali Korkmaz İstanbul
</row>

--FOR XML PATH'e parametre olarak geçilen ifade, "row" ifadesi yerine node adı olur.
SELECT AdSoyad FROM Musteri FOR XML PATH('Musteri')
--<Musteri><AdSoyad>Ali Korkmaz</AdSoyad></Musteri>
*/</pre>
<p>Eğer kolon adı olarak XML PATH&#8217;in özel ifadelerinden &#8220;data()&#8221; girilirse herhangi bir node adı oluşturulmaz sadece kolondaki veri gösterilir.
<pre name="code" class="sql">SELECT KursAd "data()" FROM Kurs FOR XML PATH
--<row>C#</row><row>VB.NET</row><row>SQL Server</row></pre>
<p>Şimdi örneğimize geri dönelim. Telefon kayıtlarını yan yana yazarken kolon adı olarak boşluğu girmesi için FOR XML PATH(&#8221;) ifadesini ayrıca &#8220;row&#8221; veya kolon adını node ismi kullanmaması sadece kolon verisini göstermesi için kolon adı olarak &#8220;data()&#8221; ifadesini kullancağız.
<pre name="code" class="sql">SELECT Telefon [data()] FROM MusteriTelefon
FOR XML PATH('')</pre>
<p><code>(0212)111  (0533)111  (0216)111  (0542)111</code> Çıkan bu sonuçtaki boşluk ifadeleri virgülle replace edelim.
<pre name="code" class="sql">SELECT MusteriId,
REPLACE(
(
	SELECT RTRIM(Telefon) [data()] FROM MusteriTelefon
	FOR XML PATH('')
),' ',',')
FROM MusteriTelefon</pre>
<p><code>1	(0212)111,(0533)111,(0216)111,(0542)111<br />
1	(0212)111,(0533)111,(0216)111,(0542)111<br />
1	(0212)111,(0533)111,(0216)111,(0542)111<br />
2	(0212)111,(0533)111,(0216)111,(0542)111<br />
2	(0212)111,(0533)111,(0216)111,(0542)111</code> <i>örnekte Telefonların sonunda boşluk bırakmaması için [data()] yerine [text()] kullanılabilir.</i><br /> Böylece her müşterinin birden fazla telefonunu tek satırda getirmiş olduk. </p>
<p>Bu işlemi yapabilmek için kullanacağımız diğer yöntem yine SQL 2005&#8242;in süper özellik olan <b>&#8220;CROSS APPLY&#8221;</b> operatörüdür. İki yeni operatör olan <b>&#8220;CROSS APPLY&#8221;</b> ve <b>&#8220;OUTER APPLY&#8221;</b> operatörler, tablo türünde sonuç döndüren fonksiyon veya subquery&#8217;lerle normal tablo veya viewleri JOIN etmemizi sağlar. En önemli özellikleri JOIN esnasında fonksiyonlara ilgili tablo ve view&#8217;a ait bir kolonu dinamik olarak parametre geçebiliyor olmamızdır. CROSS APPLY her iki tarafta eşleşen kayıtları getirirken, OUTER APPLY, eşleşen kayıt olmadığı zaman satırın kendisini ve karşılığında NULL değer getirir.
<pre name="code" class="sql">SELECT M.MusteriId,M.AdSoyad,
T.Telefonlar
FROM Musteri M CROSS APPLY(
	SELECT Telefon+',' AS [text()] FROM MusteriTelefon MT
	WHERE MT.MusteriId=M.MusteriId
	FOR XML PATH('')
) T(Telefonlar)--Kolon Adı</pre>
<p><code>1	Ahmet Kaymaz	(0212)111 ,(0533)111 ,<br />
2	Mehmet Kaymaz	(0216)111 ,(0542)111 ,<br />
3	Ayşe Güler	NULL</code></p>
 
<span class = "" style = "height: 25px;  float: left; "><iframe src="http://www.facebook.com/plugins/like.php?href=http://www.ahmetkaymaz.com/2007/04/24/kolondaki-verileri-birlestirmekconcatenate-islemi/&layout=standard&send=false&show_faces=false&width=&action=like&colorscheme=light&font=" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:px; height:25px"></iframe></span>]]></content:encoded>
			<wfw:commentRss>http://www.ahmetkaymaz.com/2007/04/24/kolondaki-verileri-birlestirmekconcatenate-islemi/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>SQL Server&#8217;da DTS için Global Variable Tanımlamak</title>
		<link>http://www.ahmetkaymaz.com/2007/02/23/sql-serverda-dts-icin-global-variable-tanimlamak/</link>
		<comments>http://www.ahmetkaymaz.com/2007/02/23/sql-serverda-dts-icin-global-variable-tanimlamak/#comments</comments>
		<pubDate>Fri, 23 Feb 2007 18:33:55 +0000</pubDate>
		<dc:creator>Ahmet Kaymaz</dc:creator>
				<category><![CDATA[Query Analyzer]]></category>

		<guid isPermaLink="false">http://www.ahmetkaymaz.com/sql-serverda-dts-icin-global-variable-tanimlamak/2007/02/23/</guid>
		<description><![CDATA[SQL Server üzerinde farklı kaynaklardan data transferi, toplu aktarımlar ve yerel işlemler için çoğu zaman Data Transformation Services (DTS) denilen Veri Transfer Servisini kullanırız. Hatta bu servis aracılığıyla hazırladığımız paketleri SQL Server Agent yönetiminde Job işlemlerine alarak belli peryotlarda çalışmasını sağlarız. Özellikle kurumsal uygulamalarda dağıtık kaynaklardan belli anlarda verileri çekmek ve üzerinde işlem yaparak yerel [...]]]></description>
			<content:encoded><![CDATA[<div class="google_plus_one"><g:plusone size="standard" count="true" url="http://www.ahmetkaymaz.com/2007/02/23/sql-serverda-dts-icin-global-variable-tanimlamak/"></g:plusone></div><p>SQL Server üzerinde farklı kaynaklardan data transferi, toplu aktarımlar ve yerel işlemler için çoğu zaman Data Transformation Services (DTS) denilen Veri Transfer Servisini kullanırız. Hatta bu servis aracılığıyla hazırladığımız paketleri SQL Server Agent yönetiminde Job işlemlerine alarak belli peryotlarda çalışmasını sağlarız. Özellikle kurumsal uygulamalarda dağıtık kaynaklardan belli anlarda verileri çekmek ve üzerinde işlem yaparak yerel veritabanlarına kaydetmek için DTS&#8217;ler vazgeçilmez bir alışkanlık haline gelir. MSDB veritabanında tutulan bu paketler, sunduğu zengin connection provider ve tasklarla ciddi bir kolaylık sağlar. Bu bölümde DTS paketleri içindeki genel değişken tanımlamanın nasıl yapılacağını ve dışardan DTS&#8217;lerin nasıl parametrik haline getirileceğini göreceğiz.<span id="more-51"></span></p>
<p>DTS paketlerinde global değişkenler(global variable), işlemleri dinamikleştirmeyi sağlar. Connection String&#8217;ten tutun da çalışacak Sql Query&#8217;lerine veya IO işlemlerine kadar birçok iş dinamik hale getirilebilir. Global değişkenler, DTS&#8217;leri dinamik kıldığı gibi diğer packagelerden değişken gönderilmesini, bir tasktan diğer taska veri taşınmasını kısaca DTS&#8217;i modüler hale getirir.<br /> Global değişkenleri, DTS paketlerinde ActiveX script içerisinde kullanabileceğimiz gibi doğrudan tasklar içerisinde çalışacak Sql Query&#8217;leri tasarlarken de kullanabiliriz. Öncelikle Sql Server Enterprise Manager&#8217;dan <b>Data Transformation Services</b> bölümünden Local Packages&#8217;i sağ tıklayıp New Package üzerinden yeni bir DTS paketi oluşturalım. DTS içerisinde sağ tıklayıp Package Properties bölümüne girelim. Buradaki <b>Global Variables</b> sekmesinde string türünde <i>Magaza</i> ve Date türünde <i>Tarih</i> isminde iki genel değişken tanımlayacağız. Ayrıca default değer vermemiz de doğru olur.<br /><img src="http://www.ahmetkaymaz.com/wp-content/uploads/DTS_Variable1.jpg"><br /> Hazırladığımız genel değişkenlerin değerini okumak için <b>Task</b> bölümünden <b>ActiveX Script Task</b> nesnesini çalışma alanına taşıyalım. Genel değişkenleri <i>DTSGlobalVariables</i> nesnesiyle çağırabiliriz.<br /><img src="http://www.ahmetkaymaz.com/wp-content/uploads/DTS_Variable2.jpg"><br /><i>Global değişkenlerin default olarak case sensitive olduğunu unutmamalıyız.</i><br /> Bu işlemden sonra çalışma alanının üst kısmında Execute düğmesine basıp çalıştırdığımızda Magaza değişkeninin değerini okumuş oluruz.<br /><img src="http://www.ahmetkaymaz.com/wp-content/uploads/DTS_Variable3.jpg"><br /> Bu şekilde dışardan bazı değerler alıp IO işlemlerini yapabiliriz. Nitekim ActiveX scriptler daha çok IO işlemler yapmak için kullanılır. Biz, burada bu değişkenleri Sql Query içerisinde kullanacağız. Bu amaçla DTS alanına bir <i>Microsoft OLE DB Provider for SQL Server</i> nesnesi taşıyıp lokaldeki sql server için bir database bağlantısı oluşturalım. Ardından bu bağlantıyı kullanarak çalışacak bir query oluşturmak için Task bölümünde <i>Execute SQL Task</i> ikonu taşıyalım. Bu task içerisinde bende bulunan CUSTOMER tablosunu sorgulayacağım. Bu querynin dışardan argüman olarak aldığı mağazanın yine dışardan aldığı tarihteki müşterilerini başka bir tabloya aktarmasını istiyorum. Query&#8217;i yazarken parametrik değerlerin yerine &#8220;?&#8221; simgesini ekliyoruz. <br /><img src="http://www.ahmetkaymaz.com/wp-content/uploads/DTS_Variable4.jpg"><br /> Ardından pencerenin altındaki parameters butonunu tıklayarak parametreleri sırasıyla eşleştirelim. <br /><img src="http://www.ahmetkaymaz.com/wp-content/uploads/DTS_Variable5.jpg"><br /> Daha sonra DTS&#8217;i kayıtedelim. DTS paketini AKAYMAZ\AKAYMAZ isminde Sql Server&#8217;da MusteriAktar ismiyle kaydettim.<br /><img src="http://www.ahmetkaymaz.com/wp-content/uploads/DTS_Variable6.jpg"></p>
<p> DTS paketleri doğrudan SQL Server&#8217;da database yapılarının bir parçası olmadığı için T-SQL kodlarıyla çalıştırmak yerine <b>DTSRUN</b> ismindeki batch dosyasıyla çalıştırırız. DTSRUN komutu, hangi sunucuda hangi DTS&#8217;i hangi argümanlarla çalıştırılacağına dair bir çok bilgiyi parametre olarak alır.<br /><img src="http://www.ahmetkaymaz.com/wp-content/uploads/DTS_Variable7.jpg"><br /> Bu DTS&#8217;i aşağıdaki syntax ile çağırabiliriz.<code>DTSRun /S "AKAYMAZ\AKAYMAZ" /N "MusteriAktar" /A "Magaza":"8"="M02" /A "Tarih":"7"="20.02.2006" /W "0" /E</code><br />/S = Server adı, WINS ismi veya IP Adresi<br />
<br />/N = Package adı<br />
<br />/A = global variable, her değişken için tekrar eder<br />
<br />&#8220;:8&#8243; string değerin geçileceğini<br />
<br />&#8220;:7&#8243; Date türünde değerin geçileceğini<br />
<br />/E = trusted login bunu yerine /U ve /P kullanılarak username ve password girilebilirdi.<br /><img src="http://www.ahmetkaymaz.com/wp-content/uploads/DTS_Variable8.jpg"></p>
<p> DTSRUN ifadesinin bu şekilde oluşturulması hepimize zor gelir. Bunun için günlük hayatımda kolaylıklar sağlayan <b>DTSRUNUI</b> toolunu tavsiye ederim. DTSRUN syntaxını görsel ortamda oluşturan bu araçta hem parametreleri hem de schedule işlemleri rahatlıkla yapılabiliri. Command Prompt üzerinden DTSRUNUI&#8217;yi çalıştıralım. Burada Sql Server sunucunu seçtikten sonra <i>Package name</i> bölümünü tıklayıp sistemdeki DTS&#8217;lerden aradığımız paketi seçelim. <br /><img src="http://www.ahmetkaymaz.com/wp-content/uploads/DTS_Variable9.jpg"><br /> Ardından <i>Advanced</i> bölümünden ek özelliklere ulaşalım. Buradaki <i>Variables</i>  bölümünden şekildeki gibi argümanları set edelim. Ve OK butoununu tıklamadan alt taraftaki <b>Generate</b> butonunu kullanarak DTSRUN&#8217;a ait syntax elde edelim.<br /><img src="http://www.ahmetkaymaz.com/wp-content/uploads/DTS_Variable10.jpg"> </p>
 
<span class = "" style = "height: 25px;  float: left; "><iframe src="http://www.facebook.com/plugins/like.php?href=http://www.ahmetkaymaz.com/2007/02/23/sql-serverda-dts-icin-global-variable-tanimlamak/&layout=standard&send=false&show_faces=false&width=&action=like&colorscheme=light&font=" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:px; height:25px"></iframe></span>]]></content:encoded>
			<wfw:commentRss>http://www.ahmetkaymaz.com/2007/02/23/sql-serverda-dts-icin-global-variable-tanimlamak/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>SQL&#8217;de UNION / UNION ALL ile birlikte ORDER BY kullanmak</title>
		<link>http://www.ahmetkaymaz.com/2007/01/02/union-union-all-ile-birlikte-order-by-kullanmak/</link>
		<comments>http://www.ahmetkaymaz.com/2007/01/02/union-union-all-ile-birlikte-order-by-kullanmak/#comments</comments>
		<pubDate>Tue, 02 Jan 2007 15:00:36 +0000</pubDate>
		<dc:creator>Ahmet Kaymaz</dc:creator>
				<category><![CDATA[Query Analyzer]]></category>

		<guid isPermaLink="false">http://www.ahmetkaymaz.com/union-union-all-ile-birlikte-order-by-kullanmak/2007/01/02/</guid>
		<description><![CDATA[UNION ve UNION ALL ifadeleri iki sorgu sonucunun birleştirilmesi için kullanılır. Tek farkı, UNION mükerrer kayıtları getirmez, UNION ALL ise tüm kayıtları olduğu gibi listeler. Önceki yazıda her grubun ilk kayıt edilmiş 2 ürününü UNION yöntemiyle getirmiştik.  Aynı yöntemi kullananarak her grubun son kayıt edilmiş 2 ürünü alacağız. Bunun için aklımıza ilk gelen query [...]]]></description>
			<content:encoded><![CDATA[<div class="google_plus_one"><g:plusone size="standard" count="true" url="http://www.ahmetkaymaz.com/2007/01/02/union-union-all-ile-birlikte-order-by-kullanmak/"></g:plusone></div><p>UNION ve UNION ALL ifadeleri iki sorgu sonucunun birleştirilmesi için kullanılır. Tek farkı, UNION mükerrer kayıtları getirmez, UNION ALL ise tüm kayıtları olduğu gibi listeler. <a href="http://www.ahmetkaymaz.com/her-gruptan-n-kayit-alma/2007/01/02/" target="_blank" class="GreyLink">Önceki yazıda her grubun ilk kayıt edilmiş 2 ürününü UNION yöntemiyle getirmiştik. </a> Aynı yöntemi kullananarak her grubun son kayıt edilmiş 2 ürünü alacağız. Bunun için aklımıza ilk gelen query şudur; tablodaki kayıtları UrunId&#8217;ye göre büyükten küçüğe sıralayıp TOP 1 ile en üsttekini almaktır. <span id="more-40"></span>Tablomuzu tekrar gözden geçirelim. .<br />
<table align="center" class="GreyTable">
<tr>
<th>
    GrupId</th>
<th>
    GrupAd</th>
</tr>
<tr>
<td>1</td>
<td>
    G1</td>
</tr>
<tr>
<td>2</td>
<td>
    G2</td>
</tr>
</table>
<p>
<table align="center" class="GreyTable">
<tr>
<th>
    UrunId</th>
<th>
    UrunAd</th>
<th>
    GrupId</th>
<th>
    Stok</th>
</tr>
<tr>
<td>1</td>
<td>
    P1</td>
<td>
    1</td>
<td>
    4</td>
</tr>
<tr>
<td>2</td>
<td>
    P2</td>
<td>
    2</td>
<td>
    6</td>
</tr>
<tr>
<td>3</td>
<td>
    P3</td>
<td>
    1</td>
<td>
    7</td>
</tr>
<tr>
<td>4</td>
<td>
    P4</td>
<td>
    2</td>
<td>
    0</td>
</tr>
<tr>
<td>5</td>
<td>
    P5</td>
<td>
    2</td>
<td>
    1</td>
</tr>
<tr>
<td>
            6</td>
<td>
            P6</td>
<td>
            1</td>
<td>
            3</td>
</tr>
</table>
<pre name="code" class="sql">SELECT TOP 2 UrunId,UrunAd FROM Urun
WHERE GrupId=1 ORDER BY UrunId DESC
UNION
SELECT TOP 2 UrunId,UrunAd FROM Urun
WHERE GrupId=2 ORDER BY UrunId DESC</pre>
<p> Burada, SQL Server&#8217;in UNION ve ORDER BY&#8217;in iç içe kullanılamayacağını anlatan hatasıyla karşılırız.<font color="red">Incorrect syntax near the keyword &#8216;UNION&#8217;.</font> UNION ile ifadeleri birleştirdiğimizde sadece en alt querynin dibinde ORDER BY kullanabiliriz.
<pre name="code" class="sql">SELECT TOP 2 GrupId,UrunId,UrunAd FROM Urun
WHERE GrupId=1
UNION
SELECT TOP 2 GrupId,UrunId,UrunAd FROM Urun
WHERE GrupId=2 ORDER BY UrunId DESC
</pre>
<p>Fakat bu durumda her SELECT sonucu ayrı ayrı değil bir bütün olarak ASC veya DESC olarak sıralanır.<br />
<table align="center" class="GreyTable">
<tr>
<th>
    GrupId</th>
<th>
    UrunId</th>
<th>
    UrunAd</th>
</tr>
<tr>
<td>
    2</td>
<td>
        4</td>
<td>
    P4</td>
</tr>
<tr>
<td>
    1</td>
<td>
    3</td>
<td>
    P3</td>
</tr>
<tr>
<td>
            2</td>
<td>
            2</td>
<td>
    P2</td>
</tr>
<tr>
<td>
            1</td>
<td>
            1</td>
<td>
    P1</td>
</tr>
</table>
<p>Oysa biz, her SELECT&#8217;in bağımsız olarak büyükten küçüğe sıralanmasını istiyoruz. Bu hatayı aşmak için asıl querymizi türemiş bir tablo(derived tables) olarak kullanacağız.
<pre name="code" class="sql">
SELECT * FROM(
	SELECT TOP 2 GrupId,UrunId,UrunAd FROM Urun
	WHERE GrupId=1 ORDER BY UrunId DESC
) AS T
UNION
SELECT * FROM (
	SELECT TOP 2 GrupId,UrunId,UrunAd FROM Urun
	WHERE GrupId=2 ORDER BY UrunId DESC
) AS T</pre>
<table align="center" class="GreyTable">
<tr>
<th>
    GrupId</th>
<th>
    UrunId</th>
<th>
    UrunAd</th>
</tr>
<tr>
<td>
    1</td>
<td>
    3</td>
<td>
    P3</td>
</tr>
<tr>
<td>
    1</td>
<td>
    6</td>
<td>
    P6</td>
</tr>
<tr>
<td>
            2</td>
<td>
        4</td>
<td>
    P4</td>
</tr>
<tr>
<td>
            3</td>
<td>
            5</td>
<td>
            P5</td>
</tr>
</table>
<p> UNION ve ORDER BY birlikte kullanıldığı zaman ORDER BY edilmiş kolonun SELECT içerisinde de listelenmesi gerekir. Aynı query mantığını kullanarak her ürün gruptan rasgele iki ürün getirelim. Her defasında farklı kayıtların gelmesi için NEWID() fonksiyonu kullanılır. Bu fonksiyon, her satıra farklı bir GUID değeri verir.
<pre name="code" class="sql">
SELECT * FROM(
	SELECT TOP 2 NEWID() RowId,GrupId,UrunId,UrunAd FROM Urun
	WHERE GrupId=1 ORDER BY NEWID()
) AS T
UNION
SELECT * FROM (
	SELECT TOP 2 NEWID() RowId,GrupId,UrunId,UrunAd FROM Urun
	WHERE GrupId=2 ORDER BY NEWID()
) AS T</pre>
<p></p>
 
<span class = "" style = "height: 25px;  float: left; "><iframe src="http://www.facebook.com/plugins/like.php?href=http://www.ahmetkaymaz.com/2007/01/02/union-union-all-ile-birlikte-order-by-kullanmak/&layout=standard&send=false&show_faces=false&width=&action=like&colorscheme=light&font=" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:px; height:25px"></iframe></span>]]></content:encoded>
			<wfw:commentRss>http://www.ahmetkaymaz.com/2007/01/02/union-union-all-ile-birlikte-order-by-kullanmak/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Her gruptan n kayıt okuma</title>
		<link>http://www.ahmetkaymaz.com/2007/01/02/her-gruptan-n-kayit-alma/</link>
		<comments>http://www.ahmetkaymaz.com/2007/01/02/her-gruptan-n-kayit-alma/#comments</comments>
		<pubDate>Tue, 02 Jan 2007 14:30:03 +0000</pubDate>
		<dc:creator>Ahmet Kaymaz</dc:creator>
				<category><![CDATA[Query Analyzer]]></category>

		<guid isPermaLink="false">http://www.ahmetkaymaz.com/her-gruptan-n-kayit-alma/2007/01/01/</guid>
		<description><![CDATA[Birbirleriyle ilişkili iki tablo düşünelim. Birinci tabloda başlık bilgileri ikinci tabloda ise bu başlığa ait detayların bulunduğunu varsayarak her başlıktan n tane detay kaydını getirmek için nasıl bir query yazmamız gerekir. Özellikle haber sitelerinin anasayfalarında her gruptan belli kriterlere uygun n kayıt getirmek veya yüksek stoklu ürün gruplarının en yüksek stoklu n tane ürününü listelemek [...]]]></description>
			<content:encoded><![CDATA[<div class="google_plus_one"><g:plusone size="standard" count="true" url="http://www.ahmetkaymaz.com/2007/01/02/her-gruptan-n-kayit-alma/"></g:plusone></div><p>Birbirleriyle ilişkili iki tablo düşünelim. Birinci tabloda başlık bilgileri ikinci tabloda ise bu başlığa ait detayların bulunduğunu varsayarak her başlıktan n tane detay kaydını getirmek için nasıl bir query yazmamız gerekir. Özellikle haber sitelerinin anasayfalarında her gruptan belli kriterlere uygun n kayıt getirmek veya yüksek stoklu ürün gruplarının en yüksek stoklu n tane ürününü listelemek için bu tür pratik querylere ihtiyaç duyarız.<br /><span id="more-41"></span> <br /> Bu türden bir query oluşturmak için örnek olarak <i>Grup</i> ve <i>Urun</i> şeklinde iki tane tablo oluşturalım.
<pre name="code" class="sql">CREATE TABLE [dbo].[Grup] (
	[GrupId] [int] IDENTITY (1, 1) NOT NULL ,
	[GrupAd] [char] (10) NULL
) ON [PRIMARY]
GO

CREATE TABLE [dbo].[Urun] (
	[UrunId] [int] IDENTITY (1, 1) NOT NULL ,
	[UrunAd] [char] (10) NULL ,
	[GrupId] [int] NULL ,
	[Stok] [int] NULL
) ON [PRIMARY]</pre>
<p> Birinci tabloda ürün grupları, ikinci tabloda ise ürün bilgileri ve stok adetleri bulunmaktadır. Örnek olarak aşağıdaki kayıtları girelim.<br />
<table align="center" class="GreyTable">
<tr>
<th>
    GrupId</th>
<th>
    GrupAd</th>
</tr>
<tr>
<td>1</td>
<td>
    G1</td>
</tr>
<tr>
<td>2</td>
<td>
    G2</td>
</tr>
</table>
<p>
<table align="center" class="GreyTable">
<tr>
<th>
    UrunId</th>
<th>
    UrunAd</th>
<th>
    GrupId</th>
<th>
    Stok</th>
</tr>
<tr>
<td>1</td>
<td>
    P1</td>
<td>
    1</td>
<td>
    4</td>
</tr>
<tr>
<td>2</td>
<td>
    P2</td>
<td>
    2</td>
<td>
    6</td>
</tr>
<tr>
<td>3</td>
<td>
    P3</td>
<td>
    1</td>
<td>
    7</td>
</tr>
<tr>
<td>4</td>
<td>
    P4</td>
<td>
    2</td>
<td>
    0</td>
</tr>
<tr>
<td>5</td>
<td>
    P5</td>
<td>
    2</td>
<td>
    1</td>
</tr>
<tr>
<td>
            6</td>
<td>
            P6</td>
<td>
            1</td>
<td>
            3</td>
</tr>
</table>
<p> Bu veriler doğrultusunda aşağıdaki işlemleri yapalım;<br /><b>Her grubun ilk veya ürününü okumak.</b><br />Gruplara ait ilk veya son ürünü okumak veya stoğu en fazla veya en düşük olan ürünleri okumak için UrunId veya Stok tutarlarından yararlanılır. Bu tür sorgularda sub query kullanılır. İç query&#8217;de Urun tablosunu GrupId&#8217;ye göre gruplayıp o gruba ait ilk veya son ürünü bulunur vey o ürünlere ait ID üzerinden ürünlerin bilgilerine erişilir.
<pre name="code" class="sql">SELECT U.GrupId,UrunId,UrunAd,Stok
FROM Urun U INNER JOIN (
	SELECT GrupId,MIN(UrunId) as MinUrunId
	FROM Urun GROUP BY GrupId
) as T ON U.GrupId=T.GrupId AND U.UrunId=T.MinUrunId</pre>
<p>
<table align="center" class="GreyTable">
<tr>
<th>
    GrupId</th>
<th>
    UrunId</th>
<th>
    UrunAd</th>
<th>
    Stok</th>
</tr>
<tr>
<td>1</td>
<td>
    1</td>
<td>
    P1</td>
<td>
        4</td>
</tr>
<tr>
<td>2</td>
<td>
    2</td>
<td>
    P2</td>
<td>
        6</td>
</tr>
</table>
<p>Yine aynı şekilde en büyük ürünleri de bulabiliriz.
<pre name="code" class="sql">SELECT U.GrupId,UrunId,UrunAd,Stok
FROM Urun U INNER JOIN (
	SELECT GrupId,MAX(UrunId) as MaxUrunId
	FROM Urun GROUP BY GrupId
) as T ON U.GrupId=T.GrupId AND U.UrunId=T.MaxUrunId</pre>
<p><b>Her grubun ilk 2 ürününü getirelim.</b><br /> Bunun önceki query&#8217;den farkı birden fazla ürünün isteniyor olmasıdır. Bilindiği Max veya MIN gibi grupsal fonksiyonlar, tek kayıt döndürür. Bu tür işlemleri kolayca yapabilmek için satırları numaralandırmak gerekir. Bunun için tablodaki IDENTITY olan UrunId kolonundan yararlanacağız. Bu numarayı kullanarak tabloyu kendisiyle JOIN edeceğiz. Burada her grubun ilk 2 kaydını getireceğimiz için her ürünü ele alıp o üründen önce kaç kayıt olup olmadığını sorgulayacağız. Kendisinden önce en fazla 2 kayıt olan ürünleri getireceğiz. Böylece o gruptaki ilk 2 kayıt gelmiş olur.
<pre name="code" class="sql">SELECT U1.GrupId,GrupAd,UrunId,UrunAd,Stok
FROM Urun U1 INNER JOIN Grup G ON U1.GrupId=G.GrupId
WHERE (SELECT COUNT(*)
	FROM Urun AS U2
	WHERE U2.GrupId = U1.GrupId AND U2.UrunId < U1.UrunId
	)< 2</pre>
<table align="center" class="GreyTable">
<tr>
<th>
    GrupId</th>
<th>
    GrupAd</th>
<th>
    UrunId</th>
<th>
    UrunAd</th>
<th>
    Stok</th>
</tr>
<tr>
<td>1</td>
<td>
    G1</td>
<td>
    1</td>
<td>
    P1</td>
<td>
        4</td>
</tr>
<tr>
<td>2</td>
<td>
    G2</td>
<td>
    2</td>
<td>
    P2</td>
<td>
        6</td>
</tr>
<tr>
<td>
    1</td>
<td>
    G1</td>
<td>
    3</td>
<td>
    P3</td>
<td>
    7</td>
</tr>
<tr>
<td>
    2</td>
<td>
    G2</td>
<td>
    4</td>
<td>
    P4</td>
<td>
    0</td>
</tr>
</table>
<p><b>Her grubun stoğu bulunan ilk 2 ürününü getirelim.</b><br /> Yukarıdaki query'e stok koşulunu da ekleyeceğiz. Bu koşulu hem içerdeki query hem de dış query'e ekleyerek doğru sonuca varırız. Eğer sadece dış query'e yazarsak ilk 2 kayıt içerisinde stoğu 0 olan kayıt olduğu için(UrunId=4) 2 nolu grubtan tek kayıt gelecektr. Sadece iç query'e yazarsak bu sefer 2.gruba ait hem 4 hem de 5 nolu ürün gelecektir. 5 nolu ürün gelir çünkü gerçekten de kendisinde önce stoğu>0 olan 2 kayıt var. Bu iki sıkıntıyı aşmak için her iki tarafa da stok koşulunu ekleyeceğiz.
<pre name="code" class="sql">SELECT U1.GrupId,GrupAd,UrunId,UrunAd,Stok
FROM Urun U1 INNER JOIN Grup G ON U1.GrupId=G.GrupId
WHERE (SELECT COUNT(*)
	FROM Urun AS U2
	WHERE U2.GrupId = U1.GrupId AND U2.UrunId < U1.UrunId
	AND Stok>0
	)<2
AND Stok > 0</pre>
<table align="center" class="GreyTable">
<tr>
<th>
    GrupId</th>
<th>
    GrupAd</th>
<th>
    UrunId</th>
<th>
    UrunAd</th>
<th>
    Stok</th>
</tr>
<tr>
<td>1</td>
<td>
    G1</td>
<td>
    1</td>
<td>
    P1</td>
<td>
        4</td>
</tr>
<tr>
<td>2</td>
<td>
    G2</td>
<td>
    2</td>
<td>
    P2</td>
<td>
        6</td>
</tr>
<tr>
<td>
    1</td>
<td>
    G1</td>
<td>
    3</td>
<td>
    P3</td>
<td>
    7</td>
</tr>
<tr>
<td>
    2</td>
<td>
    G2</td>
<td>
    5</td>
<td>
    P5</td>
<td>
        1</td>
</tr>
</table>
<p><b>Her grubun son 2 ürününü listeleyelim.</b><br />Her grubun en son kayıt edilmiş 2 ürününü getirelim. En son kayıt edilmiş ürünler, UrunId'leri en yüksek olarak ürünlerdir. Yine aynı şekilde yukarıdaki queryleri kullanacağız. Tek farkı, ürünleri sorgularken üründen sonra kayıt edilmiş ürünleri listeleyeceğiz.
<pre name="code" class="sql">SELECT U1.GrupId,GrupAd,UrunId,UrunAd,Stok
FROM Urun U1 INNER JOIN Grup G ON U1.GrupId=G.GrupId
WHERE (SELECT COUNT(*)
	FROM Urun AS U2
	WHERE U2.GrupId = U1.GrupId AND U2.UrunId <= U1.UrunId
	)>=2
ORDER BY U1.GrupId,UrunId DESC</pre>
<p>><br /><b>Her grubun son 2 ürününü listeleyelim.</b><br />Bu yazıda geliştirdiğimiz queryleri basit haliyle UNION ifadesiyle de yapabiliriz. Fakat bunun için her SELECT cümlesini manual oluşturmamız gerekir. Örneğin her grubun ilk 2 ürününü listeyelim.
<pre name="code" class="sql">SELECT TOP 2 UrunId,UrunAd FROM Urun WHERE GrupId=1
UNION
SELECT TOP 2 UrunId,UrunAd FROM Urun WHERE GrupId=2</pre>
<p> burada görüldüğü gibi yeni bir grup eklendiğinde UNION ifadesiyle yeni bir SELECT satırı eklemek gerekir. Peki UNION ile her grubun en son iki ürününü nasıl okuruz. Bunun örneğini bir sonraki yazıda yapalım.</p>
 
<span class = "" style = "height: 25px;  float: left; "><iframe src="http://www.facebook.com/plugins/like.php?href=http://www.ahmetkaymaz.com/2007/01/02/her-gruptan-n-kayit-alma/&layout=standard&send=false&show_faces=false&width=&action=like&colorscheme=light&font=" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:px; height:25px"></iframe></span>]]></content:encoded>
			<wfw:commentRss>http://www.ahmetkaymaz.com/2007/01/02/her-gruptan-n-kayit-alma/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

