SQL nə C++, nə də JavaScript. Buna görə də məntiqi ifadələrin qiymətləndirilməsi fərqlidir və bu heç də eyni şey deyil:
WHERE fncondX() AND fncondY()
= fncondX() && fncondY()
PostgreSQL sorğusunun icra planını optimallaşdırarkən
Buna görə də, hələ də prioriteti idarə etmək istəyirsinizsə, struktur olaraq etməlisiniz bu şərtləri qeyri-bərabər edin şərti ilə
Məlumat və onlarla işləmək əsasdır
# 0: RTFM
Başlanır
Qiymətləndirmə sırası vacib olduqda, konstruksiya ilə düzəldilə bilər
CASE
. Məsələn, bir cümlədə sıfıra bölünmənin qarşısını almaq üçün bu üsulWHERE
etibarsız:SELECT ... WHERE x > 0 AND y/x > 1.5;
Təhlükəsiz seçim:
SELECT ... WHERE CASE WHEN x > 0 THEN y/x > 1.5 ELSE false END;
İstifadə olunan tikinti
CASE
ifadəni optimallaşdırmadan qoruyur, ona görə də yalnız lazım olduqda istifadə edilməlidir.
# 1: tetikleme vəziyyəti
BEGIN
IF cond(NEW.fld) AND EXISTS(SELECT ...) THEN
...
END IF;
RETURN NEW;
END;
Hər şey yaxşı görünür, amma... Heç kim söz vermir ki, sərmayə qoyulur SELECT
birinci şərt yalan olarsa icra olunmayacaq. ilə düzəldin yuvalanmış IF
:
BEGIN
IF cond(NEW.fld) THEN
IF EXISTS(SELECT ...) THEN
...
END IF;
END IF;
RETURN NEW;
END;
İndi diqqətlə baxaq - trigger funksiyasının bütün bədəni "bükülmüş" oldu IF
. Və bu o deməkdir ki, heç bir şey bizə bu vəziyyəti istifadə edərək prosedurdan çıxarmağa mane olmur WHEN
-şərtlər
BEGIN
IF EXISTS(SELECT ...) THEN
...
END IF;
RETURN NEW;
END;
...
CREATE TRIGGER ...
WHEN cond(NEW.fld);
Bu yanaşma, şərt yanlış olarsa, zəmanətlə server resurslarına qənaət etməyə imkan verir.
# 2: OR/AND zəncir
SELECT ... WHERE EXISTS(... A) OR EXISTS(... B)
Əks halda, hər ikisi əldə edilə bilər EXISTS
doğru olacaq, amma hər ikisi edam olunacaq.
Ancaq onlardan birinin daha tez-tez "doğru" olduğunu dəqiq bilsək (və ya "yalan" - üçün AND
-zəncirlər) - ikincinin bir daha icra olunmaması üçün hansısa şəkildə "öz prioritetini artırmaq" mümkündürmü?
Belə çıxır ki, bu mümkündür - alqoritmik yanaşma məqalənin mövzusuna yaxındır
Gəlin bu şərtlərin hər ikisini "CASE altında itələyək":
SELECT ...
WHERE
CASE
WHEN EXISTS(... A) THEN TRUE
WHEN EXISTS(... B) THEN TRUE
END
Bu vəziyyətdə biz müəyyən etmədik ELSE
-dəyər, yəni hər iki şərt yalan olarsa CASE
geri dönəcək NULL
, kimi şərh olunur FALSE
в WHERE
- şərtlər.
Bu nümunə başqa bir şəkildə birləşdirilə bilər - dadmaq və rəngləmək üçün:
SELECT ...
WHERE
CASE
WHEN NOT EXISTS(... A) THEN EXISTS(... B)
ELSE TRUE
END
# 3: şərtləri necə yazmaq olmaz
Bu tetikleyicinin "qəribə" işə salınmasının səbəblərini təhlil etməyə iki gün sərf etdik - görək niyə.
Mənbə:
IF( NEW."Документ_" is null or NEW."Документ_" = (select '"Комплект"'::regclass::oid) or NEW."Документ_" = (select to_regclass('"ДокументПоЗарплате"')::oid)
AND ( OLD."ДокументНашаОрганизация" <> NEW."ДокументНашаОрганизация"
OR OLD."Удален" <> NEW."Удален"
OR OLD."Дата" <> NEW."Дата"
OR OLD."Время" <> NEW."Время"
OR OLD."ЛицоСоздал" <> NEW."ЛицоСоздал" ) ) THEN ...
Problem №1: Bərabərsizlik NULL-u nəzərə almır
Tutaq ki, hər şey OLD
- sahələr önəmlidi NULL
. Nə olacaq?
SELECT NULL <> 1 OR NULL <> 2;
-- NULL
Və şəraitin işlənməsi baxımından NULL
ekvivalent FALSE
, yuxarıda qeyd edildiyi kimi.
qərar: operatordan istifadə edin IS DISTINCT FROM
ROW
- bütün qeydləri bir anda müqayisə edən operator:
SELECT (NULL, NULL) IS DISTINCT FROM (1, 2);
-- TRUE
Problem № 2: eyni funksionallığın fərqli həyata keçirilməsi
Müqayisə edək:
NEW."Документ_" = (select '"Комплект"'::regclass::oid)
NEW."Документ_" = (select to_regclass('"ДокументПоЗарплате"')::oid)
Niyə əlavə investisiyalar var SELECT
? Bir funksiya to_regclass
? Niyə fərqlidir...
Gəlin düzəldək:
NEW."Документ_" = '"Комплект"'::regclass::oid
NEW."Документ_" = '"ДокументПоЗарплате"'::regclass::oid
Problem №3: bool üstünlüyü
Mənbəni formatlaşdıraq:
{... IS NULL} OR
{... Комплект} OR
{... ДокументПоЗарплате} AND
( {... неравенства} )
Vay... Əslində, məlum oldu ki, ilk iki şərtdən hər hansı birinin həqiqəti olduğu halda, bütün şərt belə olur. TRUE
, bərabərsizlikləri nəzərə almadan. Və bu heç də bizim istədiyimiz deyil.
Gəlin düzəldək:
(
{... IS NULL} OR
{... Комплект} OR
{... ДокументПоЗарплате}
) AND
( {... неравенства} )
Problem №4 (kiçik): bir sahə üçün mürəkkəb VƏ ya şərt
Əslində 3-cü yerdə məhz üç şərt olduğu üçün problemlər yaşadıq. Ancaq bunların əvəzinə mexanizmdən istifadə edərək, biri ilə əldə edə bilərsiniz coalesce ... IN
:
coalesce(NEW."Документ_"::text, '') IN ('', '"Комплект"', '"ДокументПоЗарплате"')
Elə biz də NULL
"tutmaq" və mürəkkəbdir OR
Mötərizələrlə məşğul olmaq lazım deyil.
Ümumi
Əldə etdiyimiz şeyi düzəldək:
IF (
coalesce(NEW."Документ_"::text, '') IN ('', '"Комплект"', '"ДокументПоЗарплате"') AND
(
OLD."ДокументНашаОрганизация"
, OLD."Удален"
, OLD."Дата"
, OLD."Время"
, OLD."ЛицоСоздал"
) IS DISTINCT FROM (
NEW."ДокументНашаОрганизация"
, NEW."Удален"
, NEW."Дата"
, NEW."Время"
, NEW."ЛицоСоздал"
)
) THEN ...
Və bu trigger funksiyasının yalnız istifadə edilə biləcəyini nəzərə alsaq UPDATE
mövcudluğuna görə tətik OLD/NEW
yuxarı səviyyəli vəziyyətdə, o zaman bu vəziyyət ümumiyyətlə çıxarıla bilər WHEN
-1-də göstərildiyi kimi vəziyyət...
Mənbə: www.habr.com