SQL என்பது C++ அல்ல, ஜாவாஸ்கிரிப்ட் அல்ல. எனவே, தருக்க வெளிப்பாடுகளின் மதிப்பீடு வேறுபட்டது, மேலும் இது ஒன்றும் இல்லை:
WHERE fncondX() AND fncondY()
= fncondX() && fncondY()
PostgreSQL வினவலின் செயலாக்கத் திட்டத்தை மேம்படுத்தும் போது
எனவே, நீங்கள் இன்னும் முன்னுரிமையை நிர்வகிக்க விரும்பினால், நீங்கள் கட்டமைப்பு ரீதியாக இருக்க வேண்டும் இந்த நிலைமைகளை சமமற்றதாக்கு நிபந்தனையுடன்
தரவு மற்றும் அவர்களுடன் பணிபுரிவது அடிப்படை
#0: RTFM
தொடங்குகிறது
மதிப்பீட்டின் வரிசை முக்கியமானதாக இருக்கும்போது, அதை கட்டுமானத்துடன் சரி செய்யலாம்
CASE
. எடுத்துக்காட்டாக, ஒரு வாக்கியத்தில் பூஜ்ஜியத்தால் வகுப்பதைத் தவிர்க்க இந்த வழிWHERE
நம்பமுடியாத:SELECT ... WHERE x > 0 AND y/x > 1.5;
பாதுகாப்பான விருப்பம்:
SELECT ... WHERE CASE WHEN x > 0 THEN y/x > 1.5 ELSE false END;
பயன்படுத்தப்பட்ட கட்டுமானம்
CASE
உகப்பாக்கத்திலிருந்து வெளிப்பாட்டைப் பாதுகாக்கிறது, எனவே அது தேவைப்படும்போது மட்டுமே பயன்படுத்தப்பட வேண்டும்.
#1: தூண்டுதல் நிலை
BEGIN
IF cond(NEW.fld) AND EXISTS(SELECT ...) THEN
...
END IF;
RETURN NEW;
END;
எல்லாம் நன்றாகத் தெரிகிறது, ஆனால்... முதலீடு செய்ததாக யாரும் உறுதியளிக்கவில்லை SELECT
முதல் நிபந்தனை தவறாக இருந்தால் செயல்படுத்தப்படாது. அதை சரிசெய்யவும் கூடு கட்டப்பட்டது IF
:
BEGIN
IF cond(NEW.fld) THEN
IF EXISTS(SELECT ...) THEN
...
END IF;
END IF;
RETURN NEW;
END;
இப்போது கவனமாகப் பார்ப்போம் - தூண்டுதல் செயல்பாட்டின் முழு உடலும் "சுற்றப்பட்டதாக" மாறியது IF
. இதன் பொருள் என்னவென்றால், இந்த நிலையைப் பயன்படுத்தும் நடைமுறையிலிருந்து நீக்குவதிலிருந்து எதுவும் நம்மைத் தடுக்காது WHEN
- நிபந்தனைகள்
BEGIN
IF EXISTS(SELECT ...) THEN
...
END IF;
RETURN NEW;
END;
...
CREATE TRIGGER ...
WHEN cond(NEW.fld);
நிபந்தனை தவறானதாக இருந்தால், சேவையக வளங்களை உத்தரவாதத்துடன் சேமிக்க இந்த அணுகுமுறை உங்களை அனுமதிக்கிறது.
#2: அல்லது/மற்றும் சங்கிலி
SELECT ... WHERE EXISTS(... A) OR EXISTS(... B)
இல்லையெனில், இரண்டையும் பெறலாம் EXISTS
உண்மையாக இருக்கும், ஆனால் இரண்டும் நிறைவேற்றப்படும்.
ஆனால் அவற்றில் ஒன்று "உண்மையானது" என்று உறுதியாகத் தெரிந்தால் (அல்லது "தவறு" - க்கு AND
- சங்கிலிகள்) - எப்படியாவது "அதன் முன்னுரிமையை அதிகரிக்க" முடியுமா, அதனால் இரண்டாவது மீண்டும் ஒரு முறை செயல்படுத்தப்படாது?
இது சாத்தியம் என்று மாறிவிடும் - வழிமுறை அணுகுமுறை கட்டுரையின் தலைப்புக்கு அருகில் உள்ளது
இந்த இரண்டு நிபந்தனைகளையும் "கேஸ் கீழ் தள்ளுவோம்":
SELECT ...
WHERE
CASE
WHEN EXISTS(... A) THEN TRUE
WHEN EXISTS(... B) THEN TRUE
END
இந்த வழக்கில், நாங்கள் வரையறுக்கவில்லை ELSE
மதிப்பு, அதாவது, இரண்டு நிபந்தனைகளும் தவறானவை என்றால் CASE
திரும்பும் NULL
, என விளக்கப்படுகிறது FALSE
в WHERE
- நிபந்தனைகள்.
இந்த உதாரணத்தை வேறு வழியில் இணைக்கலாம் - சுவை மற்றும் வண்ணம்:
SELECT ...
WHERE
CASE
WHEN NOT EXISTS(... A) THEN EXISTS(... B)
ELSE TRUE
END
#3: எப்படி [இல்லை] நிபந்தனைகளை எழுதுவது
இந்த தூண்டுதலின் "விசித்திரமான" தூண்டுதலுக்கான காரணங்களை பகுப்பாய்வு செய்வதில் இரண்டு நாட்கள் செலவிட்டோம் - ஏன் என்று பார்ப்போம்.
ஆதாரம்:
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 ...
சிக்கல் #1: சமத்துவமின்மை NULLக்குக் காரணமாகாது
எல்லாம் என்று வைத்துக் கொள்வோம் OLD
- புலங்கள் முக்கியம் NULL
. என்ன நடக்கும்?
SELECT NULL <> 1 OR NULL <> 2;
-- NULL
மற்றும் நிலைமைகளை வேலை செய்யும் பார்வையில் இருந்து NULL
இணையான FALSE
, மேலே குறிப்பிட்டுள்ளபடி.
முடிவு: ஆபரேட்டரைப் பயன்படுத்தவும் IS DISTINCT FROM
ROW
- ஆபரேட்டர், முழு பதிவுகளையும் ஒரே நேரத்தில் ஒப்பிடுதல்:
SELECT (NULL, NULL) IS DISTINCT FROM (1, 2);
-- TRUE
சிக்கல் எண் 2: ஒரே செயல்பாட்டின் வெவ்வேறு செயலாக்கம்
அது ஒப்பிட்டு பார்ப்போம்:
NEW."Документ_" = (select '"Комплект"'::regclass::oid)
NEW."Документ_" = (select to_regclass('"ДокументПоЗарплате"')::oid)
ஏன் கூடுதல் முதலீடுகள் உள்ளன SELECT
? ஒரு செயல்பாடு to_regclass
? ஏன் வித்தியாசமாக இருக்கிறது...
சரி செய்வோம்:
NEW."Документ_" = '"Комплект"'::regclass::oid
NEW."Документ_" = '"ДокументПоЗарплате"'::regclass::oid
சிக்கல் #3: பூல் முன்னுரிமை
மூலத்தை வடிவமைப்போம்:
{... IS NULL} OR
{... Комплект} OR
{... ДокументПоЗарплате} AND
( {... неравенства} )
அச்சச்சோ ... உண்மையில், முதல் இரண்டு நிபந்தனைகளில் ஏதேனும் உண்மை இருந்தால், முழு நிலையும் மாறுகிறது TRUE
, ஏற்றத்தாழ்வுகளைப் புறக்கணித்தல். மேலும் இது நாம் விரும்பியது அல்ல.
சரி செய்வோம்:
(
{... IS NULL} OR
{... Комплект} OR
{... ДокументПоЗарплате}
) AND
( {... неравенства} )
சிக்கல் #4 (சிறியது): ஒரு புலத்திற்கான சிக்கலான அல்லது நிபந்தனை
உண்மையில், மூன்று நிபந்தனைகள் இருந்ததால் துல்லியமாக எண். 3 இல் எங்களுக்கு சிக்கல்கள் இருந்தன. ஆனால் அவர்களுக்கு பதிலாக, நீங்கள் பொறிமுறையைப் பயன்படுத்தி ஒன்றைப் பெறலாம் coalesce ... IN
:
coalesce(NEW."Документ_"::text, '') IN ('', '"Комплект"', '"ДокументПоЗарплате"')
நாமும் அப்படித்தான் NULL
"பிடி", மற்றும் சிக்கலான OR
அடைப்புக்குறிக்குள் நீங்கள் வம்பு செய்ய வேண்டியதில்லை.
மொத்தம்
கிடைத்ததை சரி செய்வோம்:
IF (
coalesce(NEW."Документ_"::text, '') IN ('', '"Комплект"', '"ДокументПоЗарплате"') AND
(
OLD."ДокументНашаОрганизация"
, OLD."Удален"
, OLD."Дата"
, OLD."Время"
, OLD."ЛицоСоздал"
) IS DISTINCT FROM (
NEW."ДокументНашаОрганизация"
, NEW."Удален"
, NEW."Дата"
, NEW."Время"
, NEW."ЛицоСоздал"
)
) THEN ...
இந்த தூண்டுதல் செயல்பாட்டை மட்டுமே பயன்படுத்த முடியும் UPDATE
இருப்பதன் காரணமாக தூண்டுகிறது OLD/NEW
மேல் நிலை நிலையில், இந்த நிலை பொதுவாக வெளியே எடுக்கப்படலாம் WHEN
#1 இல் காட்டப்பட்டுள்ளபடி நிபந்தனை...
ஆதாரம்: www.habr.com