Transact-SQL. NULL yoxsa sıfır?

Salam Dostlar.

Bugünkü məqalədə çox maraqlı bir mövzumuz var. Bu gün NULL barədə danışacağıq. Bu barədə kifayət qədər yazılı və video materiallar var, lakin NULL barədə verilən sualların ardı kəsilmir. Bəzi hallarda sorğularda qəribə nəticələrə və anlaşılmazlıqlara səbəb olan NULL proqramçıları çox narahat edir. Buna görə də yazılı şəkildə bu mövzuya daha ətraflı izah verməyə qərarına gəldim.

NULL nədir? Bəziləri NULL deyəndə sıfır başa düşürlər, çünki NULL sıfır kimi tərcümə olunur.

Lakin irəlidə görəcəyik ki bu belə deyil, T-SQL də NULL tam başqa məqsədlər üçün istifadə olunur.

Əvvələ yadda saxlamaq lazımdır ki, NULL qiymət deyil, yəni NULL qiyməti demək düzgün deyil. NULL bildirir ki, sütundaki qiymət məlum deyil və ya yolverilməzdir. NULL sıfırın, sıfır uzunluğu olan sətrin və ya boş simvolun sinonimi deyil.

NULL necə daxil olunur? Bu iki üsulla baş verir:

  1. NULL icazə verilmiş və DEFAULT məhdudiyyətləri qoyulmamış  sütuna məlumatlar daxil edilmədikdə NULL avtomatik daxil edilir.
  2. İstifadəçi dırnaqlarsız NULL sözünün daxil etməsi yolu ilə. Əgər NULL sözü dırnaqarası yazılırsa, o N, U, L və L hərflərinin yığımı kimi çıxış edir.

Verilənlər bazasında bəzi verilənlərin qiyməti olmaya bilər. Məsələn, işçilərin cədvəlində işçinin telefon nömrəsi olmaya bilər. Və yaxud da biz bəzi məlumatları hələ dəqiq bilmirik. Məsələn, işçinin işə qəbul olunma tarixini bilirik, lakin işçi hələ işlədiyi üçün biz onun işdən azad olunma tarixini hələ bilmirik. Daha bir misal: mühərriklər cədvəlində tam elektrik mühərrikin yanacaq sərfiyatı olmadığı üçün yanacaq sərfiyatı sütununda qiyməti olmaya bilər, çünki elektrik mühərrik üçün yanacaq sərfiyatını göstərmək mənasızdır. Həmçinin bəzi hallarda səhv qiymət daxil edildikdə nəticədə NULL qayıda bilər və s.

Əksər proqramlaşdırma dillərindən fərqli olaraq SQL-də NULL sıfır, FALTH, və ya boş sətir qiymətlərindən fərqlənir. Bu SQL standartına uyğundur. Buna görə də qiyməti olmayan sütunlar üzərində riyaziyyat əməliyyatlarının nəticələri bəzilərini təəccübləndirə bilər. Məsələn, proqramçılar gözləyirlər ki, NULL olan və zaman bildirən sütuna 8 saat əlavə etdikdə nəticədə 8 saat qayıdacaq, çünki onlar adətən proqramlaşdırma dillərində olan TRUE, FALSE və UNKNOUN qiymətlərinə öyrəşiblər. Nəticədə isə NULL qayıdır.

Məsələn, belə bir sorğunun nəticəsində:

SELECT NULL + 10

Proqramçı gözləyir ki bu sorğunun nəticəsi 10 olacaq, lakin nəticədə NULL alınır. NULL sıfır deyil, buna görə də NULL qiyməti olan sütuna rəqəm əlavə edildikdə və çıxıldıqda və ya digər riyaziyyat əməliyyatları edildikdə NULL qiyməti qayıdır. Sifira 10 əlavə etsək 10 alınır. Bilinməyən qiymətə 10 əlavə etsək nəticəni bilməyəcəyik, çünki ilk rəqəmin birinin nə olduğunu bilmirdik.

Digər bir nümunəyə baxaq:

SELECT NULL + 'metn'

Burada da NULL nəticəsini alırıq.

NULL boş sətir deyil, buna görə də NULL qiyməti olan sətri hər hansı bir mətn ilə birləşdirldikdə NULL nəticəsi alınır. Mətnə mətn əlavə etsək nəticədə yeni mətn alınır. Bilinməyən mətnə mətn əlavə etsək nəticəni bilməyəcəyik, çünki ilkinin mətnin nə olduğunu bilmirdik.

Burada bir məqama diqqət etmək lazımdır. Oracle PL/SQL standartlın bu tələblərinə cavab vermir və mətn tipli verilənlərlə işlədikdə NULL boş sətirlə eyniləşdirilir. Bu istisna yalnız mətn tipli verilənlərə aiddir. Bunu niyə görə burada qeyd etdim, çünki əvvəl PL/SQL ilə məşğul olanlar və T-SQL barədə bizim dərslərimizi izləyən oxucularda anlaşılmazlıq yarana bilər.

Northwind bazası üzərində bir nümunəyə baxaq. Şəhəri “London” olan və regionu məlum olmayan işçiləri tapaq:

 

USE Northwind;
GO

SELECT * 
FROM dbo.Employees
WHERE City = 'London' AND Region = NULL

Nəticədə heçnə almırıq. Hər iki şərtimiz doğru görsənsə də bu belə deyil. Şəhər “London” olan şərt doğrudur, lakin Regionu “NULL” olan şərt doğru deyil çünki Region sütunundakı NULL onu bildirir ki, region məlum deyil, buna görə də nəticədə şərtimizin tələbləri pozulur və buna görə də heçnə almırıq.

NULL nə doğru (TRUTH) nə də ki, yanlış (FALTH) deyil, buna görə də NULL qiyməti olan sütunla AND, OR və NOT məntiqi əməliyyatların nəticələri fərqli ola bilər.

Bunu aydın anlamaq üçün belə bir müqayisə edək. Tutaq ki, Elçinin 25 yaşı var, Pərvizin yaşı isə yaşı məlum deyil. Əgər sizdən soruşsalar ki, yaşda Elçin böyükdür yoxsa Pərviz, sizin yeganə cavabınız “bilmirəm” olacaq. Əgər sizdən soruşsalar ki, Elçinlə Pərviz həmyaşıddırlarmı, sizin yeganə cavabınız “bilmirəm” olacaq. Əgər sizdən soruşsalar ki, Elçinlə Pərvizin yaşlarını cəmləsək neçə alınacaq, sizin yeganə cavabınız “bilmirəm” olacaq. Tutaq ki, Fəridin də yaşını bilmirik. Əgər sizdən soruşsalar ki, Pərvizin yaşı Fəridin yaşı ilə eynidir mi, sizin  cavabınız yenə də “bilmirəm” olacaq. Bu onu göstərir ki, niyə görə NULL = NULL müqayisəsi yenə də NULL ilə nəticələnir.

NULL üzrə filtrləmə qoymaq üçün IS NULLIS NOT NULL predikatları istifadə olunur. Diqqət edin: IS NULLIS NOT NULL predikatlarında operatorlar ayrı-ayrı yazılır. Məsələn: belə bir sorğulara baxaq. Birincidə regionu bilinməyən işçiləri, ikincidə isə regionu dəqiq bilinən işçiləri tapaq:

SELECT * 
FROM dbo.Employees
WHERE Region = NULL
SELECT * 
FROM dbo.Employees
WHERE Region <> NULL

Bu cür yazılış düzgün deyil və heç bir nəticə qaytarmır. NULL qiymətləri üzrə filtr qoyaq. Birinci regionu bilinməyən işçiləri tapaq:

SELECT * 
FROM dbo.Employees
WHERE Region IS NULL

IS_NULL

Daha sonra regionu dəqiq bilinən, yəni NULL olmayan, işçiləri tapaq:

SELECT * 
FROM dbo.Employees
WHERE Region IS NOT NULL

IS_NOT_NULL

Bəzi hallarda nəticədə alınan NULL başqa qiymətlərlə əvəz edilir. Məsələn, proqram təminatı üzrə hesabat veriləndə nəticədə NULL deyil onu əvəz edən hər hansı bir qiymətin olması məsləhətdir. Sorğuda NULL-u başqa qiymətlə əvəz etmək üçün 3 üsul mövcuddur:

ISNULL funksiyası ilə, COALECSE funksiyası ilə və CASE ifadəsi ilə. Bunların hər birisinə nümunə üzərində baxaq. Northwind bazasının Employees cədvəli ilə işləyəcəyik. Bu cədvəldə ad və soyad sütunları vardır. Tutaq ki, rəhbərlik tərəfindən proqram təminatında belə bir dəyişiklik etmək tapşırığı verilir: “Eyni ad və soyadda bir neçə işçi vardır. Buna gərə də işçilərin atasının adını da proqram təminatına əlavə  edin”. Biz təbii ki, Employees cədvəlində əlavə sütun yaradırıq və bəzi işçilərin atasının adlarını da bu sütuna əlavə edirik. Mən Northwind bazasında bəzi dəyişiklər etdim: Employees cədvəlində atasının adı inisialı (Middle_init) sütununu əlavə etdim:

ALTER TABLE dbo.Employees ADD Middle_init CHAR (2)

Daha sonra həmin sütuna bəzi işçilərin atasının adlarınının inisiallarını, yəni ilk hərfini  əlavə etdim:

UPDATE dbo.Employees SET Middle_init = 'C.'
WHERE EmployeeID = 5

UPDATE dbo.Employees SET Middle_init = 'M.'
WHERE EmployeeID = 2

Qoyulan tapşırığa əsasən ad, soyad və atasinin adı inisialından ibarət tam adı çıxaraq:

SELECT FirstName + ' ' + LastName + ' ' + Middle_init AS FullName 
FROM dbo.Employees

Netice1

Bütün bu dəyişiklərdən sonra proqram təminatında səhvlər əmələ gəlir və ya proqram tam dayanır. Rəhbərlik nəticə tələb edir, proqram təminatı işləmir, hamı gözləyir.

Sorğunu analız edəndə görürük ki, nəticədə cəmi iki sətirdə tam ad alındı. Bu sətirlərin atasının adı inisialı da vardır. Qalan digər sətirlərdə heç olmasa ad və soyad qalmalı idi. Burada isə NULL görürük. Bəs nə baş verdi? Yuxarıda qeyd etdiyimiz kimi, biz boş sətrə mətn əlavə etmək istədik. SQL Server tərəfindən bu sorğu belə anlaşılır: məlum olmayan nəyinsə üzərinə mətn əlavə olunması cəhdi var, buna görə də nəticə məlum deyil.

Qoyulan tapşırığa əsasən sorğumuzu normal hala salaq. Bunun üçün NUL-u boş sətirlə əvəz etməliyik. Qeyd etdiyimiz kimi, bunun üçün bizim üç üsulumuz var. Hər 3 üsulla sorğumuzu yazaq:

--ISNULL funksiyasi vasitesile 
SELECT FirstName + ' ' + LastName + ' ' + ISNULL(Middle_init, '') AS FullName 
FROM dbo.Employees

-- COALESCSE funksiyasi vasitesile 
SELECT FirstName + ' ' + LastName + ' ' + COALESCE(Middle_init, '') AS FullName 
FROM dbo.Employees

--CASE ifadesi ile 
SELECT FirstName + ' ' + LastName + ' ' + 
CASE WHEN Middle_init IS NULL THEN '' ELSE Middle_init END AS FullName 
FROM dbo.Employees

Full_Name_2

Hər üç sorğu eyni nəticə verir.

ISNULL funksiyası T-SQL dilinə məxsus funksiyadır. Diqqət edin: ISNULL funksiyası bitişik yazılır və onun əksi ISNOTNULL mövcud deyil. COALESCE funksiyası  SQL standartlın funksiyasıdır. CASE ifadəsi də standarta uyğundur, lakin NULL ilə bağlı sorğularda adətən istifadə olunmur. COALESCE funksiyası ISNULL funksiyası eyni nəticə verir, lakin bunların arasında fərqlər var. COALESCE funksiyası daha geniş imkanlara malikdir. Bu funksiya barədə biz növbəti dərslərimizdə ətraflı danışacağıq. Təcrübəyə əsasən sırf SQL Serverlə işləyən bazalar üçün ISNULL funksiyası məsləhətdir, universal, yəni bütün VBİS-lərdə işləyən bazalar üçün COALESCE funksiyasının istifadəsi məsləhətdir.

Beləliklə, bugünkü məqalənin də sonuna gəlib çatdıq. NULL nədir sualına ətraflı cavab verməyə çalışdıq. Bu məqalə uzun müddətdir üzərində çalışdığım Microsoft Transact-SQL barədə kitabımdan bir çıxarışdır.

Növbəti məqalələrdə görüşənədək.

Diqqətinizə görə təşəkkür edirəm.

Səs: +30. Bəyənilsin Zəifdir

Müəllif: Rauf Khalafov

Şərh yazın