Ang SQL ay hindi C++, at hindi rin ito JavaScript. Samakatuwid, ang pagsusuri ng mga lohikal na expression ay naiiba, at hindi ito ang parehong bagay:
WHERE fncondX() AND fncondY()
= fncondX() && fncondY()
Habang ino-optimize ang execution plan ng isang PostgreSQL query
Samakatuwid, kung gusto mo pa ring pamahalaan ang priyoridad, kailangan mong structurally gawing hindi pantay ang mga kundisyong ito na may kondisyon
Data at pakikipagtulungan sa kanila ang batayan
#0: RTFM
Nagsisimula
Kapag ang pagkakasunud-sunod ng pagsusuri ay mahalaga, maaari itong ayusin sa pamamagitan ng konstruksyon
CASE
. Halimbawa, sa ganitong paraan upang maiwasan ang paghahati ng zero sa isang pangungusapWHERE
hindi mapagkakatiwalaan:SELECT ... WHERE x > 0 AND y/x > 1.5;
Ligtas na opsyon:
SELECT ... WHERE CASE WHEN x > 0 THEN y/x > 1.5 ELSE false END;
Ang ginamit na konstruksiyon
CASE
pinoprotektahan ang expression mula sa pag-optimize, kaya dapat lang itong gamitin kung kinakailangan.
#1: kundisyon ng trigger
BEGIN
IF cond(NEW.fld) AND EXISTS(SELECT ...) THEN
...
END IF;
RETURN NEW;
END;
Mukhang maganda ang lahat, ngunit... Walang nangangako na ang namuhunan SELECT
ay hindi isasagawa kung mali ang unang kundisyon. Ayusin ito sa nakapugad IF
:
BEGIN
IF cond(NEW.fld) THEN
IF EXISTS(SELECT ...) THEN
...
END IF;
END IF;
RETURN NEW;
END;
Ngayon tingnan nating mabuti - ang buong katawan ng pag-andar ng pag-trigger ay naging "nakabalot" sa IF
. At nangangahulugan ito na walang pumipigil sa amin na alisin ang kundisyong ito mula sa pamamaraang ginagamit WHEN
-kondisyon
BEGIN
IF EXISTS(SELECT ...) THEN
...
END IF;
RETURN NEW;
END;
...
CREATE TRIGGER ...
WHEN cond(NEW.fld);
Binibigyang-daan ka ng diskarteng ito na i-save ang mga mapagkukunan ng server na may garantiya kung mali ang kundisyon.
#2: O/AT chain
SELECT ... WHERE EXISTS(... A) OR EXISTS(... B)
Kung hindi, maaari itong makuha na pareho EXISTS
ay magiging totoo, ngunit kapwa mapapatupad.
Ngunit kung alam nating sigurado na ang isa sa kanila ay "totoo" nang mas madalas (o "mali" - para sa AND
-chains) - posible bang kahit papaano ay "dagdagan ang priyoridad nito" upang ang pangalawa ay hindi maisakatuparan muli?
Ito ay lumalabas na posible - ang algorithm na diskarte ay malapit sa paksa ng artikulo
"I-shove under CASE" lang natin ang parehong kundisyong ito:
SELECT ...
WHERE
CASE
WHEN EXISTS(... A) THEN TRUE
WHEN EXISTS(... B) THEN TRUE
END
Sa kasong ito, hindi namin tinukoy ELSE
-value, iyon ay, kung ang parehong mga kundisyon ay mali CASE
babalik NULL
, na binibigyang kahulugan bilang FALSE
Π² WHERE
- kundisyon.
Ang halimbawang ito ay maaaring pagsamahin sa ibang paraan - sa panlasa at kulay:
SELECT ...
WHERE
CASE
WHEN NOT EXISTS(... A) THEN EXISTS(... B)
ELSE TRUE
END
#3: paano [hindi] magsulat ng mga kundisyon
Gumugol kami ng dalawang araw sa pagsusuri sa mga dahilan para sa "kakaibang" pag-trigger ng trigger na ito - tingnan natin kung bakit.
Pinagmulan:
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 ...
Problema #1: Ang hindi pagkakapantay-pantay ay hindi isinasaalang-alang ang NULL
Ipagpalagay natin na ang lahat OLD
-ang mga patlang ay mahalaga NULL
. Ano ang mangyayari?
SELECT NULL <> 1 OR NULL <> 2;
-- NULL
At mula sa punto ng view ng pagtatrabaho sa mga kondisyon NULL
katumbas FALSE
, gaya ng nabanggit sa itaas.
desisyon: gumamit ng operator IS DISTINCT FROM
ROW
-operator, naghahambing ng buong mga tala nang sabay-sabay:
SELECT (NULL, NULL) IS DISTINCT FROM (1, 2);
-- TRUE
Problema numero 2: iba't ibang pagpapatupad ng parehong pag-andar
Ihambing natin ang:
NEW."ΠΠΎΠΊΡΠΌΠ΅Π½Ρ_" = (select '"ΠΠΎΠΌΠΏΠ»Π΅ΠΊΡ"'::regclass::oid)
NEW."ΠΠΎΠΊΡΠΌΠ΅Π½Ρ_" = (select to_regclass('"ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠΎΠΠ°ΡΠΏΠ»Π°ΡΠ΅"')::oid)
Bakit may extra investments SELECT
? Isang function to_regclass
? Bakit iba...
Ayusin natin:
NEW."ΠΠΎΠΊΡΠΌΠ΅Π½Ρ_" = '"ΠΠΎΠΌΠΏΠ»Π΅ΠΊΡ"'::regclass::oid
NEW."ΠΠΎΠΊΡΠΌΠ΅Π½Ρ_" = '"ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠΎΠΠ°ΡΠΏΠ»Π°ΡΠ΅"'::regclass::oid
Problema #3: bool precedence
I-format natin ang pinagmulan:
{... IS NULL} OR
{... ΠΠΎΠΌΠΏΠ»Π΅ΠΊΡ} OR
{... ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠΎΠΠ°ΡΠΏΠ»Π°ΡΠ΅} AND
( {... Π½Π΅ΡΠ°Π²Π΅Π½ΡΡΠ²Π°} )
Oops ... Sa katunayan, lumabas na sa kaso ng katotohanan ng alinman sa unang dalawang kundisyon, ang buong kundisyon ay nagiging TRUE
, binabalewala ang mga hindi pagkakapantay-pantay. At hindi ito ang gusto namin.
Ayusin natin:
(
{... IS NULL} OR
{... ΠΠΎΠΌΠΏΠ»Π΅ΠΊΡ} OR
{... ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠΎΠΠ°ΡΠΏΠ»Π°ΡΠ΅}
) AND
( {... Π½Π΅ΡΠ°Π²Π΅Π½ΡΡΠ²Π°} )
Problema #4 (maliit): kumplikado O kundisyon para sa isang field
Actually, nagkaproblema kami sa No. 3 precisely because there were three conditions. Ngunit sa halip na sa kanila, maaari kang makakuha ng isa, gamit ang mekanismo coalesce ... IN
:
coalesce(NEW."ΠΠΎΠΊΡΠΌΠ΅Π½Ρ_"::text, '') IN ('', '"ΠΠΎΠΌΠΏΠ»Π΅ΠΊΡ"', '"ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠΎΠΠ°ΡΠΏΠ»Π°ΡΠ΅"')
Ganun din tayo NULL
"huli", at kumplikado OR
Hindi mo kailangang mag-abala sa mga panaklong.
Sa kabuuan
Ayusin natin ang nakuha natin:
IF (
coalesce(NEW."ΠΠΎΠΊΡΠΌΠ΅Π½Ρ_"::text, '') IN ('', '"ΠΠΎΠΌΠΏΠ»Π΅ΠΊΡ"', '"ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠΎΠΠ°ΡΠΏΠ»Π°ΡΠ΅"') AND
(
OLD."ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠ°ΡΠ°ΠΡΠ³Π°Π½ΠΈΠ·Π°ΡΠΈΡ"
, OLD."Π£Π΄Π°Π»Π΅Π½"
, OLD."ΠΠ°ΡΠ°"
, OLD."ΠΡΠ΅ΠΌΡ"
, OLD."ΠΠΈΡΠΎΠ‘ΠΎΠ·Π΄Π°Π»"
) IS DISTINCT FROM (
NEW."ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠ°ΡΠ°ΠΡΠ³Π°Π½ΠΈΠ·Π°ΡΠΈΡ"
, NEW."Π£Π΄Π°Π»Π΅Π½"
, NEW."ΠΠ°ΡΠ°"
, NEW."ΠΡΠ΅ΠΌΡ"
, NEW."ΠΠΈΡΠΎΠ‘ΠΎΠ·Π΄Π°Π»"
)
) THEN ...
At dahil magagamit lang ang trigger function na ito sa UPDATE
trigger dahil sa presensya OLD/NEW
sa mataas na antas na kondisyon, kung gayon ang kundisyong ito ay karaniwang maaaring alisin WHEN
-kondisyon tulad ng ipinapakita sa #1...
Pinagmulan: www.habr.com