SQL ùn hè micca C++, nè JavaScript. Dunque, a valutazione di l'espressioni lògichi hè diversu, è questu ùn hè micca listessa cosa:
WHERE fncondX() AND fncondY()
= fncondX() && fncondY()
Mentre ottimisate u pianu di esecuzione di una query PostgreSQL
Dunque, sè vo vulete ancu gestisce a priorità, avete bisognu di strutturalmente rende queste cundizioni ineguali cù cundizzioni
Dati è travaglià cun elli hè a basa
#0: RTFM
Partendu
Quandu l'ordine di valutazione hè impurtante, pò esse riparatu cù a custruzzione
CASE
. Per esempiu, questu modu per evità a divisione per zero in una fraseWHERE
inaffidabile:SELECT ... WHERE x > 0 AND y/x > 1.5;
Opzione sicura:
SELECT ... WHERE CASE WHEN x > 0 THEN y/x > 1.5 ELSE false END;
A custruzzione utilizata
CASE
prutege l'espressione da l'ottimisazione, cusì deve esse usatu solu quandu hè necessariu.
#1: cundizione di trigger
BEGIN
IF cond(NEW.fld) AND EXISTS(SELECT ...) THEN
...
END IF;
RETURN NEW;
END;
Tuttu pare vede bè, ma... Nimu prumetti chì l'investitu SELECT
ùn serà micca eseguitu se a prima cundizione hè falsa. Fix lu cun nidificatu IF
:
BEGIN
IF cond(NEW.fld) THEN
IF EXISTS(SELECT ...) THEN
...
END IF;
END IF;
RETURN NEW;
END;
Avà fighjulemu cun cura - tuttu u corpu di a funzione di scatula hè diventatu "imballatu". IF
. È questu significa chì nunda ùn ci impedisce di sguassà sta cundizione da a prucedura cù l'usu WHEN
- cundizioni
BEGIN
IF EXISTS(SELECT ...) THEN
...
END IF;
RETURN NEW;
END;
...
CREATE TRIGGER ...
WHEN cond(NEW.fld);
Stu approcciu permette di salvà risorse di u servitore cù una guaranzia se a cundizione hè falsa.
#2: catena OR/AND
SELECT ... WHERE EXISTS(... A) OR EXISTS(... B)
Altrimenti, pò esse ottenutu chì i dui EXISTS
serà "veru", ma tutti dui seranu eseguiti.
Ma se sapemu di sicuru chì unu di elli hè "veru" assai più spessu (o "falsu" - per AND
-chains) - hè pussibule di qualchì manera "aumentà a so priorità" per chì u sicondu ùn hè micca eseguitu una volta?
Ci hè chì hè pussibule - l'approcciu algoritmicu hè vicinu à u tema di l'articulu
Fighjemu solu "shove under CASE" e duie cundizioni:
SELECT ...
WHERE
CASE
WHEN EXISTS(... A) THEN TRUE
WHEN EXISTS(... B) THEN TRUE
END
In questu casu ùn avemu micca definitu ELSE
-value, vale à dì, se i dui cundizioni sò falsi CASE
tornerà NULL
, chì hè interpretatu cum'è FALSE
в WHERE
- cundizioni.
Questu esempiu pò esse cumminatu in un altru modu - à u gustu è u culore:
SELECT ...
WHERE
CASE
WHEN NOT EXISTS(... A) THEN EXISTS(... B)
ELSE TRUE
END
# 3: cumu [micca] scrive e cundizioni
Avemu passatu dui ghjorni per analizà i motivi di l'attivazione "strana" di stu trigger - vedemu perchè.
Fonte:
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 ...
Prublemu #1: A inuguaglianza ùn conta micca per NULL
Assumimu chì tuttu OLD
- i campi importavanu NULL
. Chì succede ?
SELECT NULL <> 1 OR NULL <> 2;
-- NULL
È da u puntu di vista di travaglià e cundizioni NULL
equivalente FALSE
, cum'è citatu sopra.
dicisioni: usu operatore IS DISTINCT FROM
ROW
-operatore, paragunendu registri interi in una volta:
SELECT (NULL, NULL) IS DISTINCT FROM (1, 2);
-- TRUE
Prublemu numeru 2: implementazione differente di a stessa funziunalità
Comparare:
NEW."Документ_" = (select '"Комплект"'::regclass::oid)
NEW."Документ_" = (select to_regclass('"ДокументПоЗарплате"')::oid)
Perchè ci hè un investimentu extra quì? SELECT
? Una funzione to_regclass
? Perchè hè diversu...
Fixemu:
NEW."Документ_" = '"Комплект"'::regclass::oid
NEW."Документ_" = '"ДокументПоЗарплате"'::regclass::oid
Prublemu #3: precedenza bool
Formatemu a fonte:
{... IS NULL} OR
{... Комплект} OR
{... ДокументПоЗарплате} AND
( {... неравенства} )
Oops ... In fattu, hè risultatu chì in u casu di a verità di qualsiasi di e prime duie cundizioni, tutta a cundizione diventa TRUE
, senza riguardu à l'ineguaglianze. È questu ùn hè micca in tuttu ciò chì vuliamu.
Fixemu:
(
{... IS NULL} OR
{... Комплект} OR
{... ДокументПоЗарплате}
) AND
( {... неравенства} )
Prublemu #4 (picculu): cundizione OR cumplessa per un campu
In verità, avemu avutu prublemi in u N ° 3 precisamente perchè ci eranu trè cundizioni. Ma invece di elli, pudete piglià cun unu, usendu u mecanismu coalesce ... IN
:
coalesce(NEW."Документ_"::text, '') IN ('', '"Комплект"', '"ДокументПоЗарплате"')
So noi NULL
"avemu catturà", è difficiule OR
Ùn ci hè micca bisognu di fussi cù parentesi.
Tuttu
Fixemu ciò chì avemu avutu:
IF (
coalesce(NEW."Документ_"::text, '') IN ('', '"Комплект"', '"ДокументПоЗарплате"') AND
(
OLD."ДокументНашаОрганизация"
, OLD."Удален"
, OLD."Дата"
, OLD."Время"
, OLD."ЛицоСоздал"
) IS DISTINCT FROM (
NEW."ДокументНашаОрганизация"
, NEW."Удален"
, NEW."Дата"
, NEW."Время"
, NEW."ЛицоСоздал"
)
) THEN ...
È datu chì sta funzione trigger pò esse usata solu in UPDATE
-trigger per via di a dispunibilità OLD/NEW
in a cundizione di livellu superiore, allura sta cundizione pò generalmente esse eliminata WHEN
-condizione cum'è mostra in # 1 ...
Source: www.habr.com