SQL Server Programlama ve Yönetim İpuçları – II

Daha önce yazdığımız ipuçlarına ek olarak bu yazıda aşağıdaki ipuçlarını vereceğiz.

  • SQL Server servisi her çalıştığında bazı komutları nasıl çalıştırabiliriz.
  • SQL Server Enterprise Management konsolde açılmıyor.
  • “IS NULL” ve “= NULL” arasındaki fark nedir.
  • COALESCE(), ISNULL() ve NULLIF() fonksiyonlar arasındaki fark nedir.
  • NEWSEQUENTIALID() ve NEWID() arasındaki fark nedir.
  • TRUNCATE ile DELETE arasındaki fark nedir.
  • T-SQL aracılığıyla uzaktan erişim nasıl açılır/kapatılır.
  • Veritabanı dosyalarının büyüklüğünü her gün mail ile nasıl alabilirim.
  • İki saat arasındaki farkı saat olarak yazdırmak


1 – Sql Server her çalıştığında belli bir procedure çalıştırmak
Bir SQL Server yöneticisi olarak her SQL Server çalıştığında standart bazı stored procedure veya jobların devreye girip çalışmasına ihtiyaç duymuşumdur. Örneğin SQL Server başladığında otomatik olarak SQL Agent veya SQL Trace araçlarını başlatmak bir gereksinim olabilir. Bir Windows servisi olan MSSQLSERVER servisi başladığında belli komutların da çalışmasın için sp_procoption yordamını sunar.

sp_procoption [ @ProcName = ] 'procedure'
    , [ @OptionName = ] 'option'
    , [ @OptionValue = ] 'value' 

İlk parametre, SQL Server başladığı zaman otomatik olarak çalıştırılacak yordamı belirtir. İkinci parametre startup değerini alıp ilk parametredeki yordamın otomatik çalıştırılacağını belirtir. Üçüncü parametre ikinci parametredeki koşulun değerini belirtip on (true veya on) veya off (false veya off) değerlerini alır.
Her SQL Server açıldığında belirlediğimiz bir tabloya açılış saatini yazdıralım. Bu basit log tablosunun şeması şu şekilde olsun.

USE Master
GO
CREATE TABLE BaslangicLog
(
	LogId INT IDENTITY(1,1) NOT NULL,
	Tarih DATETIME NOT NULL
)

Bu tabloya kayıt atacak olan bir procedure oluşturalım.

USE Master
GO
CREATE PROCEDURE LogTabloYaz
AS
SET NOCOUNT ON
INSERT INTO BaslangicLog  VALUES (GETDATE())

LogTabloYaz yordamını başlangıç yordamı olarak düzenlemek için aşağıdaki gibi sp_procoption yordamına parametre olarak geçiyoruz.

USE Master
GO
sp_procoption @ProcName = 'LogTabloYaz',
              @OptionName = 'startup',
              @OptionValue = 'on'

Bu işlemden sonra SQL Server servisinin yeniden başlattığımızda BaslangicLog tablosuna bir log satırının kaydedildiğini görürüz.
Buna benzer olarak bazı kodların SQL Server Agent’in başlangıcına bağlamak istersek bunun için bir Job tanımlayıp o Job için oluşturulacak olan schedule’da bir zaman tanımlaması yapmak yerine “Start Automatically when SQL Server Agent Starts” seçeneği işaretlenir.

Servisin başlangıcında çalışan yordamların ExecIsStartup özelliği true olarak set edilmiştir. Aşağıdaki script bu yordamları listeler.

SELECT * FROM sysobjects
WHERE OBJECTPROPERTY (id,'ExecIsStartup') = 1

2 – SQL Server Enterprise Management konsolde açılmıyor
Bazı aksi durumlarda Enterprise Management’i açmaya çalışırken aşağıdaki hatayla karşılaşırız.
MMC cannot open the file C:\Program Files\Microsoft SQL Server\80\Tools\BINN\SQL Server Enterprise Manager.MSC.
Bu hata mesajı Enterprise Manager’in Microsoft Yönetim Konsolu (Microsoft Management Console-MMC) üzerinde açılmasını sağlayan MSC dosyasının bozulmasından kaynaklanmaktadır. Bunu için aşağıdaki işlemler yapılır.

  1. “Start » Run” alanına girip MMC komutunu çalıştıralım
  2. Console aracında File menüsünden – “Add/Remove Snap-in.” menüsünü tıklayalım
  3. Açılan pencerede Add. düğmesini tıklayalım.
  4. Listeden “Microsoft SQL Enterprise Manager” aracını seçip “Add » Close” düğmelerini tıklayalım.
  5. Ok düğmesini tıklayıp konsole geri dönelim.
  6. File menüsünden “Save As.” menüsü aracılığıyla dosyayı orijinal MMC dosyasının üstüne yazalım.
  7. MSC dosyasını “C:\Program Files\Microsoft SQL Server\80\Tools\BINN\SQL Server Enterprise Manager.MSC” olarak kaydedebileceğimiz gibi farklı bir isimde de kayıt edebiliriz.

3 – “IS NULL” ve “= NULL” arasındaki fark nedir
SQL Server üzerinde null yani geçerli olmayan veri (boş) türündeki kayıtlar üzerinde filtreleme yapılırken WHERE bölümünde nasıl bir ifadenin yazılacağı ANSI_NULLS özelliğine bağlıdır. ANSI_NULLS özelliği, Eşit-Equals (=) veya Eşit Değil-Not Equal to (<>) kıyaslamalarında null kayıtlarına nasıl davranılacağını belirtir.

SET ANSI_NULLS {ON | OFF}

ANSI_NULLS özelliği ON olarak düzenlendiğinde null kayıtlarla yapılan karşılaştırmalar false sonucunu döndürür yani arama listesine dahil edilmez. Bu durumda aşağıdaki sorgu AdSoyad kolonunda null kayıtlar bulunsa bile herhangi bir kayıt döndürmez.

SELECT * FROM Musteri WHERE AdSoyad=NULL

ANSI_NULLS özelliğini OFF olarak düzenlendiğinde null kayıtlar diğer kayıtlarla karşılaştırılabilir duruma getirilir. Bu durumda üstteki sorguya null olan kayıtlar dahil edilmiş olur.
SQL Server varsayılan olarak “SET ANSI_NULLS ON” modundadır. Bu değer aynı zamanda SQL-92’nın standartıdır. Bu standart dahilinde null kayıtlar üzerinde filtreleme yapmak için “IS NULL” veya “IS NOT NULL” koşul deyimi kullanılır.

SELECT * FROM Musteri WHERE AdSoyad IS NULL

Yeri gelmişken aşağıdaki maddeleri hatırlatmamızda fayda var;
SQL Server’de aggregate fonksiyonlarında (Average, Count, Maximum, Minimum, Sum) null kayıtlar dikkate alınmaz. Aşağıdaki tabloyu düşünelim.

c1 c2
10 10
20 20
30 30
NULL 40

Bu tablodaki c1 ve c2 kolonları üzerinde aşağıdaki sorguları çalıştırdığımızda açıklama olarak verilmiş olan sonuçlar döner.

SELECT COUNT(*) FROM Table1 --4
SELECT COUNT(c2) FROM Table1 --4
SELECT COUNT(c1) FROM Table1 --3
SELECT COUNT(DISTINCT c1) FROM Table1 --3
SELECT AVG(c1) FROM Table1 --20
SELECT AVG(c2) FROM Table1 --25
SELECT MIN(c1) FROM Table1 --10
SELECT MAX(c1) FROM Table1 --30

GROUP BY ile yapılan gruplamalarda null kayıtlar gözönünde bulundurulur.

SELECT c1,COUNT(*) [Satır Sayısı],
COUNT(c1) [c1'in Dolu Olduğu Satır Sayısı] FROM Table1
GROUP BY c1

Bu sorgunun sonucu aşağıdaki gibi olur.

c1 Satır Sayısı c1’in Dolu Olduğu Satır Sayısı
NULL 1 0
10 1 1
20 1 1
30 1 1

SQL Server’de kayıtlar ORDER BY ile sıralanırken varsayılan olarak null kayıtlar ilk sırada gelir. Malesef T-SQL’de PL/SQL’de bulunan ve ORDER BY ile birlikte NULLS FIRST veya NULLS LAST ifadeleri bulunmamaktadır. null kayıtların sıralama yönünü değiştirmek için programcının çözüm sunması gerekir. Bunun için aşağıdaki gibi UNION ifadesi veya ISNULL(), COALESCE() fonksiyonları kullanılabilir.

SELECT * FROM Table1 WHERE c1 IS NOT NULL
UNION ALL
SELECT * FROM Table1 WHERE c1 IS NULL

Bu ifade c1 ismindeki sütununda null kayıtları listenin sonuna yazdırır. Bu kolon sayısal bir kolon olduğu için null kayıtları ISNULL() aracılığıyla en yüksek rakam olacak şekilde düzenlersek yine null kayıtlar listenin sonunda çıkmış olur.

SELECT * FROM Table1 ORDER BY ISNULL(c1,99999)

4 – ISNULL, COALESCE ve NULLIF arasındaki fark nedir
ISNULL() fonksiyonu dışarıdan iki parametre alıp ilk parametre geçerli olmayan veri Boş (null) içeriyorsa ikici parametredeki ifadeyi değilse kendisini döndürür. Aşağıdaki ifade ilk parametre null olduğu için ikinci parametredeki ifadeyi yani “İstanbul” değerini döndürür.

SELECT ISNULL(NULL,'Istanbul')

COALESCE() yordamı birçok parametre alıp parametreler arasında ilk null olmayan kaydı döndürür.

COALESCE ( expression [ ,...n ] )

Eğer tüm değerler null ise COALESCE fonksiyonu geriye null döndürür. Aşağıdaki ifade geriye 2008 değerini döndürür.

SELECT COALESCE(null,null,2008,'SQL Server')

null kayıtlar için kullanılan diğer fonksiyon ise NULLIF() fonksiyonudur. İki parametre alan bu fonksiyon iki parametre birbirine eşit olduğu durumda geriye null diğer durumda birinci parametreyi döndürür.

NULLIF ( expression , expression )

NULLIF(c1, c2) ifadesi aşağıdaki gibi çalışır.

CASE WHEN c1 = c2 THEN NULL ELSE c1 END

Bu fonksiyon genellikle sıfıra bölünme hatasının oluşma durumlarında tercih edilir. Aşağıdaki ifadede (c1+c2) toplamı sıfır olduğu zaman sorgu hataya neden olacaktır.

SELECT c1 / (c1 + c2) FROM  Table1

Bunu engellemek için CASE ve WHERE koşulları kullanılır.

SELECT c1 / (c1 + c2) FROM  Table1
WHERE c1 + c2 
Özellikler büyük sorgularda WHERE koşulunun bulunması bir performans sorunu olabilir. Sifira bölünme hatasından kurtulmak için NULLIF kullanılabilir. Sorguyu aşağıdaki gibi (c1+c2) işlemi sıfır olduğu zaman null döndürecek şekilde değiştirirsek çalışma anında hatadan kurtulmuş oluruz.
[sql]SELECT c1 / NULLIF(c1+c2,0) FROM Table1

Bu sorgu sonucunda c1 ve c2’nin toplamının sıfır olduğu satırlarda sonuç kolonu null olarak döner.
5 – NEWSEQUENTIALID() ve NEWID() arasındaki fark nedir
SQL Server’da uniqueidentifier türünde tekil değer üretmek için NEWID() fonksiyonu kullanılır. Bilindiği gibi uniqueidentifier türü (GUID), bilgisayarın tarih, saat ve diğer özellikleri referans alınarak eşsiz olarak oluşturulan 43F5BE27-A029-4FEA-B13E-74C47F465E10 gibi 32 basamaklı hexadecimal bir sayıdır. SQL Server uniqueidentifier türünde değer üretmek için 2005 versiyonuyla birlikte NEWSEQUENTIALID() fonksiyonu da sunulmaktadır. NEWID() ve NEWSEQUENTIALID() en önemli fark, NEWID() fonksiyonu rastgele değer üretirken NEWSEQUENTIALID() sıralı değer üretir. Diğer fark ise NEWID() her yerde kullanılabilirken NEWSEQUENTIALID() tabloda uniqueidentifier türündeki kolonlarda sadece DEFAULT constraint olarak kullanılabilir.

CREATE TABLE Tablo
    (Kolon uniqueidentifier DEFAULT NEWSEQUENTIALID()) 

NEWSEQUENTIALID() fonksiyonu da sıralı değer ürettiği için güvenli uygulamalarda tercih edilmemelidir. Bununla birlikte insert, delete, update gibi işlemlerde NEWSEQUENTIALID() ile oluşturulmuş kolonun üzerindeki index NEWID() ile oluşturulmuş kolon üzerindeki indexe göre daha performanslı olacaktır. Çünkü bu işlemlerde sözkonusu kolondaki değerler her defasında yeniden sıralanacaktır. NEWSEQUENTIALID() ile oluşturulmuş kolon zaten sıralı olduğu için pek zaman kaybettirmeyecektir.
6 – TRUNCATE ile DELETE arasındaki fark nedir
Tablodaki kayıtları silmek için kullanılan bu iki komut arasındaki farklar şunlardır;

  • TRUNCATE, tablodaki tüm kayıtları siler. DELETE ise WHERE içerisinde verilmiş koşula uyan satırları siler. WHERE koşulu tanımlanmamışsa tüm kayıtları siler. Bu yüzden WHERE koşulu TRUNCATE ile birlikte kullanılamaz.
  • DELETE işlemi her satırı fiziksel olarak siler ve silme işlemini log dosyasında saklar. TRUNCATE ise kayıtları fiziksel olarak silmek yerine bu kayıtların bulunduğu data page’leri silinmiş olarak işaretler ve extentleri yeni kullanılabilmesi için boş olarak işaretler. Bu yüzden DELETE işlemi özellikle büyük tablolarda daha uzun sürer ve o log dosyasının büyümesine neden olur. Bununla birlikte TRUNCATE işleminin hiç log tutmadığını söylememiz doğru olmaz sadece DELETE işleminden farklı olarak her satır için data page için basit loglama yapar.
  • TRUNCATE işleminden sonra log tutulmadığı için ROLLBACK yapılamaz. DELETE işleminde ise ROLLBACK ihtimali mevcuttur. Bu yüzden TRUNCATE komutunun bilinçli kullanılması gerekir.
  • Üzerinde “Foreign Key Constraint” tanımlı olan tabloya TRUNCATE işlemi uygulanamaz. Öncelikle bu tür constraint’lerin silinmesi gerekir.
  • Bilindiği gibi normal şartlar altında IDENTITY tipindeki bir kolondaki tüm satırlar DELETE ile silinse bile identity değeri en son kaldığı yerden devam eder yani sıfırlanmaz. Identity alanını ilk değerinden başlatmak için tablonun TRUNCATE ile silinmesi gerekir.
  • DELETE işleminde varsa tablo üzerindeki DELETE TRIGGER çağrılır fakat TRUNCATE işleminde doğrudan datanın kendisi üzerinde bir değişiklik olmadığı için silme trigger’i çağrılmaz.
  • Transactional replication veya merge replication modelinde yayınlanan tablolar üzerinde TRUNCATE işlemi uygulanamaz.
  • Tablo üzerinde TRUNCATE işlemini uygulamak için ALTER yetkilerine, DELETE işlemi içinse DELETE yetkilerine sahip olmak gerekir.
  • TRUNCATE komutu bir DDL operasyonu, DELETE ise bir DML operasyonu olarak tanımlanır.

Bildiğin gibi verileri MDF dosyası içerisindeki extent’ler içerisinde data page’ler içerisinde bulunur. Her data page içerisinde dolu ve boş alanı ayıran bir sınır mevcuttur. Bu sınıra high water mark (hwm) denilir. Tablo okumaları bu sınıra kadar olur. Kayıt eklendikçe bu sınır biraz daha genişlenir. TRUNCATE komutunun yaptığı iş hwm işaretçisini sıfırlamasıdır. DELETE işlemi bu işaretçiyi geriye doğru çekmez.
7 – T-SQL aracılığıyla uzaktan erişim nasıl açılır/kapatılır
Doğrudan T-SQL kodlarını kullanarak SQL Server 2005’i uzaktan erişime açıp kapatamıyoruz. Bunu ancak “SQL Server 2005 Surface Area Configuration” aracından yapabiliriz. Fakat bu aracın yazdığı registry alanında değişiklik yapacak bir T-SQL yordamı yazılırsa o zaman doğrudan SQL scriptleriyle bu işlem yapılabilir. Sunucu üzerinde kurulu SQL Server’in uzaktan erişilebilirlik durumu aşağıdaki registry anahtarında tutulur.
HKLM\SOFTWARE\Microsoft\Microsoft SQL Server\< ınstance adı="">\MSSQLServer\SuperSocketNetLib
master.dbo.xp_regread yordamını kullanarak bu alan üzerinde Np (PipeName) ve Tcp (TcpPort) anahtarları düzenlenebilir.
8 – Veritabanı dosyalarının büyüklüğünü her gün mail ile nasıl alabilirim.
Bunun için SQL Server Agent üzerinde bir Job hazırlanır. Job, veritabanlarına ait data ve log dosyalarının büyüklüğünü okuyup SQL Mail veya Database Mail aracılığıyla ilgili kullanıcıya gönderir. SQL Server üzerinde tanımlı veritabanlarının dosyaları hakkındaki bilgileri SQL Server 2000’de sysfiles, SQL 2005’te sys.database_files tablosunda tutulmaktadır. Aşağıdaki sorgu mevcut veritabanının dosyalarının büyüklüğünü listeler.

SELECT RTRIM(name) [Dosya Adı]
,CAST(((SIZE * 8.00)/1024.00) AS DECIMAL(18,2)) [Büyüklüğü (MB)]
FROM sys.database_files

Bu sorguyu her veritabanı için çalıştırmak için sp_msforeachdb yordamı kullanılabilir. Bu listeyi ilgili kişilere mail olarak atmak için geçici bir tablo oluşturulur ve her veritabanının dosyaları geçici tabloya aktarılır ardından geçici tablo mail olarak gönderilir. Aşağıdaki kodlarda bunun örneğini bulabilirsiniz.

--Geçici tabloyu oluşturalım
CREATE TABLE #T (Name char(50),
	DatabaseSize numeric(9,2))

--Her veritabanı için sorguyu çalıştırıp sonucu geçici tabloya aktaralım
EXECUTE sp_msforeachdb 'INSERT INTO #T SELECT RTRIM(name)
,CAST(((SIZE * 8.00)/1024.00) AS DECIMAL(18,2))
FROM [?].sys.database_files'

--Mail olarak atacağımız HTML tablosunu oluşturalım
DECLARE @tableHTML  NVARCHAR(MAX) ;

SET @tableHTML =
    N'
<img src="https://www.ahmetkaymaz.com/wp-content/uploads/SQL_Server_Database_Buyuklugu_1.jpg"/>
SQL Server'de mail gönderme işlemlerinin hangi yöntemlerle yapılabileceğini <a href="https://www.ahmetkaymaz.com/2008/02/20/sql-server-ftp-mail-gonderme/">bu linkte</a> daha detaylı bulabilirsiniz.
<b><u>9 - İki saat arasındaki farkı saat olarak yazdırmak</u></b>
[sql]DECLARE @Saat1 char(5), @Saat2 char(5)

SELECT @Saat1='09.57', @Saat2='12.35'

SELECT convert(varchar(5),
	dateadd(day,0,replace(@Saat2,'.',':'))-
	dateadd(day,0,replace(@Saat1,'.',':')),108)

02:38

SQL Server Programlama ve Yönetim İpuçları – II” hakkında 7 yorum

  1. UNSAL OSMA

    aşağıdaki kodlarlar boş hücrleri kontrol ettiriyorum ki aynı tarih,otel ve tennis kortuna ikincikez kayıt yapılmasın diye ama en son zaman1 parametresinde sorun yaşıyorum sorgularken boluda olsa boş diyo nasıl çözebilirim.Dim baglan As New SqlConnection(“Data Source=UNSAL\SQLEXPRESS;Initial Catalog=coskun;Integrated Security=True;Pooling=False”)
    Dim komut As New SqlCommand(“select count(*) from tennis where tarih=@tarih and otel=@otel and kort=@kort and zaman1=@zaman1¨, baglan)
    komut.Parameters.Add(“@tarih”, SqlDbType.DateTime).Value = DateTimePicker3.Text
    If CheckBox1.Checked Then
    komut.Parameters.Add(“@otel”, SqlDbType.NVarChar).Value = CheckBox1.Text
    End If
    If CheckBox2.Checked Then
    komut.Parameters.Add(“@otel”, SqlDbType.NVarChar).Value = CheckBox2.Text
    End If
    If CheckBox3.Checked Then
    komut.Parameters.Add(“@kort”, SqlDbType.NVarChar).Value = CheckBox3.Text
    End If
    If CheckBox4.Checked Then
    komut.Parameters.Add(“@kort”, SqlDbType.NVarChar).Value = CheckBox4.Text
    End If
    komut.Parameters.Add(“@zaman1¨, SqlDbType.NVarChar).Value = TextBox3.Text
    Baglan.Open()
    Dim VarMi As Integer = komut.ExecuteScalar
    baglan.Close()
    If VarMi > 0 Then
    MsgBox(“Kayıt var.”)
    Else
    MsgBox(“Kayıt yok.”)
    End If
    End If

    Cevapla
  2. Ahmet Kaymaz Yazar

    Boş derken neyi kastediyorsunuz. TextBox3.Text değerini ekrana yazdırabiliyor musunuz. Bu değer dolu olduğu zaman sorguyu SQL Server’e gönderdiğiniz nasıl bir T-SQL script’i oluşuyor orada bu @zaman1 parametresinin değeri ne görünüyor. Bütün bunlara bakmak gerekiyor.

    Cevapla
  3. Aytuğ Halil AKAR

    Ellerinize sağlık, detaylı ve buna rağmen çok başarılı anlatımlar. Faydalandık inşeallah.

    Cevapla
  4. Ahmet ÇEKEN

    Eline sağlık. Kadıköy Halk Eğitim Merkezi Veritabanı kursumuz için çok faydalı oldunuz…

    Cevapla

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir