SQL er ekki C++, né JavaScript. Þess vegna er mat á rökrænum tjáningum öðruvísi og þetta er alls ekki það sama:
WHERE fncondX() AND fncondY()
= fncondX() && fncondY()
Þó að hagræða framkvæmdaráætlun PostgreSQL fyrirspurnar
Þess vegna, ef þú vilt samt stjórna forgangi, þarftu að skipuleggja gera þessi skilyrði ójöfn með skilyrtum
Gögn og vinna með þau er grunnurinn
#0: RTFM
Byrjar
Þegar matsröðin er mikilvæg er hægt að laga hana með smíðinni
CASE
. Til dæmis, svona til að forðast deilingu með núll í setninguWHERE
óáreiðanlegt:SELECT ... WHERE x > 0 AND y/x > 1.5;
Öruggur valkostur:
SELECT ... WHERE CASE WHEN x > 0 THEN y/x > 1.5 ELSE false END;
Byggingin sem notuð var
CASE
verndar tjáninguna fyrir hagræðingu, þannig að það ætti aðeins að nota þegar nauðsyn krefur.
#1: kveikja ástand
BEGIN
IF cond(NEW.fld) AND EXISTS(SELECT ...) THEN
...
END IF;
RETURN NEW;
END;
Allt virðist líta vel út, en... Enginn lofar að fjárfest SELECT
verður ekki keyrt ef fyrsta skilyrðið er rangt. Lagaðu það með hreiður IF
:
BEGIN
IF cond(NEW.fld) THEN
IF EXISTS(SELECT ...) THEN
...
END IF;
END IF;
RETURN NEW;
END;
Nú skulum við skoða vandlega - allur líkaminn af kveikjuaðgerðinni reyndist vera "vafinn inn". IF
. Og þetta þýðir að ekkert kemur í veg fyrir að við fjarlægjum þetta ástand úr málsmeðferðinni WHEN
-skilyrði
BEGIN
IF EXISTS(SELECT ...) THEN
...
END IF;
RETURN NEW;
END;
...
CREATE TRIGGER ...
WHEN cond(NEW.fld);
Þessi aðferð gerir þér kleift að vista netþjónaauðlindir með ábyrgð ef ástandið er rangt.
#2: EÐA/OG keðja
SELECT ... WHERE EXISTS(... A) OR EXISTS(... B)
Annars er hægt að fá að bæði EXISTS
mun vera satt, en báðir verða teknir af lífi.
En ef við vitum með vissu að ein þeirra er "sönn" miklu oftar (eða "ósönn" - fyrir AND
-keðjur) - er hægt að "auka forgang sinn" einhvern veginn þannig að sá seinni sé ekki keyrður aftur?
Það kemur í ljós að það er mögulegt - reiknirit nálgunin er nálægt efni greinarinnar
Við skulum bara „skoða undir CASE“ bæði þessi skilyrði:
SELECT ...
WHERE
CASE
WHEN EXISTS(... A) THEN TRUE
WHEN EXISTS(... B) THEN TRUE
END
Í þessu tilviki skilgreindum við ekki ELSE
-gildi, það er að segja ef bæði skilyrðin eru röng CASE
kem aftur NULL
, sem er túlkað sem FALSE
в WHERE
- skilyrði.
Þetta dæmi er hægt að sameina á annan hátt - eftir smekk og lit:
SELECT ...
WHERE
CASE
WHEN NOT EXISTS(... A) THEN EXISTS(... B)
ELSE TRUE
END
#3: hvernig á að [ekki] skrifa skilyrði
Við eyddum tveimur dögum í að greina ástæðurnar fyrir „furðulegri“ kveikju þessarar kveikju - við skulum sjá hvers vegna.
Heimild:
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 ...
Vandamál #1: Ójöfnuður gerir ekki grein fyrir NULL
Gerum ráð fyrir að allt OLD
-reitir skiptu máli NULL
. Hvað mun gerast?
SELECT NULL <> 1 OR NULL <> 2;
-- NULL
Og frá því sjónarmiði að vinna út skilyrðin NULL
jafngildi FALSE
, eins og fyrr segir.
ákvörðun: nota stjórnanda IS DISTINCT FROM
ROW
-operator, ber saman heilar færslur í einu:
SELECT (NULL, NULL) IS DISTINCT FROM (1, 2);
-- TRUE
Vandamál númer 2: mismunandi útfærsla á sömu virkni
Bera saman:
NEW."Документ_" = (select '"Комплект"'::regclass::oid)
NEW."Документ_" = (select to_regclass('"ДокументПоЗарплате"')::oid)
Hvers vegna eru aukafjárfestingar SELECT
? Aðgerð to_regclass
? Af hverju er það öðruvísi...
Við skulum laga:
NEW."Документ_" = '"Комплект"'::regclass::oid
NEW."Документ_" = '"ДокументПоЗарплате"'::regclass::oid
Vandamál #3: bool forgangur
Við skulum forsníða upprunann:
{... IS NULL} OR
{... Комплект} OR
{... ДокументПоЗарплате} AND
( {... неравенства} )
Úbbs ... Reyndar kom í ljós að ef um er að ræða sannleika einhvers af fyrstu tveimur skilyrðunum breytist allt ástandið í TRUE
, án tillits til ójöfnuðar. Og þetta er alls ekki það sem við vildum.
Við skulum laga:
(
{... IS NULL} OR
{... Комплект} OR
{... ДокументПоЗарплате}
) AND
( {... неравенства} )
Vandamál #4 (lítið): flókið EÐA ástand fyrir einn reit
Reyndar áttum við í vandræðum í nr. 3 einmitt vegna þess að það voru þrjú skilyrði. En í stað þeirra geturðu komist af með einn með því að nota vélbúnaðinn coalesce ... IN
:
coalesce(NEW."Документ_"::text, '') IN ('', '"Комплект"', '"ДокументПоЗарплате"')
Það erum við líka NULL
"grípa", og flókið OR
Þú þarft ekki að tuða með sviga.
Alls
Við skulum laga það sem við fengum:
IF (
coalesce(NEW."Документ_"::text, '') IN ('', '"Комплект"', '"ДокументПоЗарплате"') AND
(
OLD."ДокументНашаОрганизация"
, OLD."Удален"
, OLD."Дата"
, OLD."Время"
, OLD."ЛицоСоздал"
) IS DISTINCT FROM (
NEW."ДокументНашаОрганизация"
, NEW."Удален"
, NEW."Дата"
, NEW."Время"
, NEW."ЛицоСоздал"
)
) THEN ...
Og í ljósi þess að aðeins er hægt að nota þessa kveikjuaðgerð í UPDATE
kveikja vegna nærverunnar OLD/NEW
í efri stigi ástandi, þá er almennt hægt að taka þetta ástand út í WHEN
-ástand eins og sýnt er í #1...
Heimild: www.habr.com