SQL sio C++, na sio JavaScript. Kwa hivyo, hesabu ya misemo ya kimantiki hufanyika tofauti, na hii sio kitu sawa:
WHERE fncondX() AND fncondY()
= fncondX() && fncondY()
Katika mchakato wa kuboresha mpango wa utekelezaji wa swala la PostgreSQL
Kwa hivyo, ikiwa bado unataka kusimamia kipaumbele, unahitaji kuitengeneza kufanya masharti haya kutokuwa sawa kwa kutumia masharti
Data na kufanya kazi nao ni msingi
#0: RTFM
Kuanzia
Wakati mpangilio wa tathmini ni muhimu, inaweza kunaswa kwa kutumia muundo
CASE
. Kwa mfano, hii ni njia ya kuzuia mgawanyiko kwa sifuri katika sentensiWHERE
asiyeaminika:SELECT ... WHERE x > 0 AND y/x > 1.5;
Chaguo salama:
SELECT ... WHERE CASE WHEN x > 0 THEN y/x > 1.5 ELSE false END;
Ubunifu uliotumika kwa njia hii
CASE
hulinda usemi dhidi ya uboreshaji, kwa hivyo inapaswa kutumika tu inapohitajika.
#1: hali ya kichochezi
BEGIN
IF cond(NEW.fld) AND EXISTS(SELECT ...) THEN
...
END IF;
RETURN NEW;
END;
Kila kitu kinaonekana kuwa kizuri, lakini ... Hakuna mtu anayeahidi kwamba uwekezaji SELECT
haitatekelezwa ikiwa sharti la kwanza ni la uwongo. Hebu turekebishe na kiota IF
:
BEGIN
IF cond(NEW.fld) THEN
IF EXISTS(SELECT ...) THEN
...
END IF;
END IF;
RETURN NEW;
END;
Sasa hebu tuangalie kwa uangalifu - mwili mzima wa kazi ya trigger "imefungwa" ndani IF
. Hii ina maana kwamba hakuna kitu kinatuzuia kuondoa hali hii kutoka kwa utaratibu wa kutumia WHEN
-masharti
BEGIN
IF EXISTS(SELECT ...) THEN
...
END IF;
RETURN NEW;
END;
...
CREATE TRIGGER ...
WHEN cond(NEW.fld);
Mbinu hii imehakikishwa kuokoa rasilimali za seva wakati hali si kweli.
#2: AU/NA mnyororo
SELECT ... WHERE EXISTS(... A) OR EXISTS(... B)
Vinginevyo, unaweza kuishia na zote mbili EXISTS
itakuwa "kweli", lakini zote mbili zitatimizwa.
Lakini ikiwa tunajua kwa hakika kuwa mmoja wao ni "kweli" mara nyingi zaidi (au "uongo" - kwa AND
-minyororo) - inawezekana kwa namna fulani "kuongeza kipaumbele chake" ili ya pili isitekelezwe tena?
Inageuka kuwa inawezekana - mbinu ya algorithmic iko karibu na mada ya makala
Hebu "tusukume" masharti haya yote mawili chini ya KESI:
SELECT ...
WHERE
CASE
WHEN EXISTS(... A) THEN TRUE
WHEN EXISTS(... B) THEN TRUE
END
Katika kesi hii hatukufafanua ELSE
-thamani, yaani, ikiwa masharti yote mawili ni ya uwongo CASE
itarudi NULL
, ambayo inafasiriwa kama FALSE
Π² WHERE
-masharti.
Mfano huu unaweza kuunganishwa kwa njia zingine - kulingana na ladha na rangi:
SELECT ...
WHERE
CASE
WHEN NOT EXISTS(... A) THEN EXISTS(... B)
ELSE TRUE
END
#3: jinsi [si] kuandika masharti
Tulitumia siku mbili kuchambua sababu za operesheni "ya kushangaza" ya kichochezi hiki - wacha tuone ni kwanini.
Chanzo:
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 ...
Tatizo #1: ukosefu wa usawa hauheshimu NULL
Hebu fikiria kwamba kila kitu OLD
-mashamba yalikuwa na maana NULL
. Nini kitatokea?
SELECT NULL <> 1 OR NULL <> 2;
-- NULL
Na kutoka kwa mtazamo wa kufanya kazi nje ya masharti NULL
sawa FALSE
, kama ilivyoelezwa hapo juu.
uamuzi: tumia opereta IS DISTINCT FROM
ROW
- mwendeshaji, kulinganisha rekodi nzima mara moja:
SELECT (NULL, NULL) IS DISTINCT FROM (1, 2);
-- TRUE
Tatizo #2: utekelezaji tofauti wa utendakazi sawa
Hebu tulinganishe:
NEW."ΠΠΎΠΊΡΠΌΠ΅Π½Ρ_" = (select '"ΠΠΎΠΌΠΏΠ»Π΅ΠΊΡ"'::regclass::oid)
NEW."ΠΠΎΠΊΡΠΌΠ΅Π½Ρ_" = (select to_regclass('"ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠΎΠΠ°ΡΠΏΠ»Π°ΡΠ΅"')::oid)
Kwa nini kuna uwekezaji wa ziada hapa? SELECT
? Kitendaji to_regclass
? Kwa nini ni tofauti? ..
Hebu turekebishe:
NEW."ΠΠΎΠΊΡΠΌΠ΅Π½Ρ_" = '"ΠΠΎΠΌΠΏΠ»Π΅ΠΊΡ"'::regclass::oid
NEW."ΠΠΎΠΊΡΠΌΠ΅Π½Ρ_" = '"ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠΎΠΠ°ΡΠΏΠ»Π°ΡΠ΅"'::regclass::oid
Tatizo #3: kipaumbele cha uendeshaji wa bool
Wacha tupange chanzo:
{... IS NULL} OR
{... ΠΠΎΠΌΠΏΠ»Π΅ΠΊΡ} OR
{... ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠΎΠΠ°ΡΠΏΠ»Π°ΡΠ΅} AND
( {... Π½Π΅ΡΠ°Π²Π΅Π½ΡΡΠ²Π°} )
Lo ... Kwa kweli, ikawa kwamba ikiwa yoyote ya masharti mawili ya kwanza ni ya kweli, hali nzima inageuka TRUE
, bila kuzingatia usawa. Na hii sio kabisa tuliyotaka.
Hebu turekebishe:
(
{... IS NULL} OR
{... ΠΠΎΠΌΠΏΠ»Π΅ΠΊΡ} OR
{... ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠΎΠΠ°ΡΠΏΠ»Π°ΡΠ΅}
) AND
( {... Π½Π΅ΡΠ°Π²Π΅Π½ΡΡΠ²Π°} )
Tatizo #4 (ndogo): changamano AU hali ya sehemu moja
Kweli, tulikuwa na matatizo katika Nambari 3 kwa usahihi kwa sababu kulikuwa na masharti matatu. Lakini badala yao unaweza kupata na moja, kwa kutumia utaratibu coalesce ... IN
:
coalesce(NEW."ΠΠΎΠΊΡΠΌΠ΅Π½Ρ_"::text, '') IN ('', '"ΠΠΎΠΌΠΏΠ»Π΅ΠΊΡ"', '"ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠΎΠΠ°ΡΠΏΠ»Π°ΡΠ΅"')
Kwa hiyo sisi NULL
"tutashika", na ngumu OR
Hakuna haja ya kuweka uzio na mabano.
Katika jumla ya
Wacha turekodi kile tulichonacho:
IF (
coalesce(NEW."ΠΠΎΠΊΡΠΌΠ΅Π½Ρ_"::text, '') IN ('', '"ΠΠΎΠΌΠΏΠ»Π΅ΠΊΡ"', '"ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠΎΠΠ°ΡΠΏΠ»Π°ΡΠ΅"') AND
(
OLD."ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠ°ΡΠ°ΠΡΠ³Π°Π½ΠΈΠ·Π°ΡΠΈΡ"
, OLD."Π£Π΄Π°Π»Π΅Π½"
, OLD."ΠΠ°ΡΠ°"
, OLD."ΠΡΠ΅ΠΌΡ"
, OLD."ΠΠΈΡΠΎΠ‘ΠΎΠ·Π΄Π°Π»"
) IS DISTINCT FROM (
NEW."ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠ°ΡΠ°ΠΡΠ³Π°Π½ΠΈΠ·Π°ΡΠΈΡ"
, NEW."Π£Π΄Π°Π»Π΅Π½"
, NEW."ΠΠ°ΡΠ°"
, NEW."ΠΡΠ΅ΠΌΡ"
, NEW."ΠΠΈΡΠΎΠ‘ΠΎΠ·Π΄Π°Π»"
)
) THEN ...
Na ukizingatia kuwa kitendaji hiki cha kichochezi kinaweza kutumika tu ndani UPDATE
-anzisha kwa sababu ya kupatikana OLD/NEW
katika hali ya juu, basi hali hii inaweza kuwekwa ndani WHEN
-hali, kama inavyoonyeshwa katika #1...
Chanzo: mapenzi.com