PostgreSQL ಆಂಟಿಪ್ಯಾಟರ್ನ್ಸ್: SQL ನಲ್ಲಿ ಸ್ಥಿತಿಯ ಮೌಲ್ಯಮಾಪನ

SQL C++ ಅಲ್ಲ, ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್ ಅಲ್ಲ. ಆದ್ದರಿಂದ, ತಾರ್ಕಿಕ ಅಭಿವ್ಯಕ್ತಿಗಳ ಮೌಲ್ಯಮಾಪನವು ವಿಭಿನ್ನವಾಗಿದೆ, ಮತ್ತು ಇದು ಒಂದೇ ವಿಷಯವಲ್ಲ:

WHERE fncondX() AND fncondY()

= fncondX() && fncondY()

PostgreSQL ಪ್ರಶ್ನೆಯ ಕಾರ್ಯಗತಗೊಳಿಸುವ ಯೋಜನೆಯನ್ನು ಉತ್ತಮಗೊಳಿಸುವಾಗ ಸಮಾನ ಪರಿಸ್ಥಿತಿಗಳನ್ನು ನಿರಂಕುಶವಾಗಿ "ಮರುಹೊಂದಿಸಬಹುದು", ವೈಯಕ್ತಿಕ ದಾಖಲೆಗಳಿಗಾಗಿ ಅವುಗಳಲ್ಲಿ ಯಾವುದನ್ನೂ ಲೆಕ್ಕ ಹಾಕಬೇಡಿ, ಅನ್ವಯಿಕ ಸೂಚ್ಯಂಕದ ಸ್ಥಿತಿಯನ್ನು ಉಲ್ಲೇಖಿಸಿ ... ಸಂಕ್ಷಿಪ್ತವಾಗಿ, ನೀವು ಊಹಿಸಿಕೊಳ್ಳುವುದು ಸುಲಭವಾದ ಮಾರ್ಗವಾಗಿದೆ ನಿರ್ವಹಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ ಅವು ಯಾವ ಕ್ರಮದಲ್ಲಿ ಇರುತ್ತವೆ (ಮತ್ತು ಅವುಗಳನ್ನು ಲೆಕ್ಕ ಹಾಕಲಾಗುತ್ತದೆಯೇ) ಸಮಾನ ಪರಿಸ್ಥಿತಿಗಳು.

ಆದ್ದರಿಂದ, ನೀವು ಇನ್ನೂ ಆದ್ಯತೆಯನ್ನು ನಿರ್ವಹಿಸಲು ಬಯಸಿದರೆ, ನೀವು ರಚನಾತ್ಮಕವಾಗಿ ಮಾಡಬೇಕಾಗುತ್ತದೆ ಈ ಪರಿಸ್ಥಿತಿಗಳನ್ನು ಅಸಮಾನಗೊಳಿಸಿ ಷರತ್ತುಬದ್ಧ ಜೊತೆ ಅಭಿವ್ಯಕ್ತಿಗಳು и ನಿರ್ವಾಹಕರು.

PostgreSQL ಆಂಟಿಪ್ಯಾಟರ್ನ್ಸ್: SQL ನಲ್ಲಿ ಸ್ಥಿತಿಯ ಮೌಲ್ಯಮಾಪನ
ಡೇಟಾ ಮತ್ತು ಅವರೊಂದಿಗೆ ಕೆಲಸ ಮಾಡುವುದು ಆಧಾರವಾಗಿದೆ ನಮ್ಮ VLSI ಸಂಕೀರ್ಣದ, ಆದ್ದರಿಂದ ಅವುಗಳ ಮೇಲಿನ ಕಾರ್ಯಾಚರಣೆಗಳನ್ನು ಸರಿಯಾಗಿ ಮಾತ್ರವಲ್ಲದೆ ಪರಿಣಾಮಕಾರಿಯಾಗಿಯೂ ನಿರ್ವಹಿಸುವುದು ನಮಗೆ ಬಹಳ ಮುಖ್ಯ. ಅಭಿವ್ಯಕ್ತಿ ಮೌಲ್ಯಮಾಪನದಲ್ಲಿ ದೋಷಗಳನ್ನು ಮಾಡಬಹುದಾದ ಕಾಂಕ್ರೀಟ್ ಉದಾಹರಣೆಗಳನ್ನು ನೋಡೋಣ ಮತ್ತು ಅವುಗಳ ದಕ್ಷತೆಯನ್ನು ಸುಧಾರಿಸಲು ಯೋಗ್ಯವಾಗಿದೆ.

#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-ಸರಪಳಿಗಳು) - ಎರಡನೆಯದನ್ನು ಮತ್ತೊಮ್ಮೆ ಕಾರ್ಯಗತಗೊಳಿಸದಂತೆ ಹೇಗಾದರೂ "ಅದರ ಆದ್ಯತೆಯನ್ನು ಹೆಚ್ಚಿಸಲು" ಸಾಧ್ಯವೇ?

ಇದು ಸಾಧ್ಯ ಎಂದು ಅದು ತಿರುಗುತ್ತದೆ - ಅಲ್ಗಾರಿದಮಿಕ್ ವಿಧಾನವು ಲೇಖನದ ವಿಷಯಕ್ಕೆ ಹತ್ತಿರದಲ್ಲಿದೆ PostgreSQL ಆಂಟಿಪ್ಯಾಟರ್ನ್‌ಗಳು: ಅಪರೂಪದ ಪ್ರವೇಶವು ಸೇರುವಿಕೆಯ ಮಧ್ಯಭಾಗವನ್ನು ತಲುಪುತ್ತದೆ.

ಈ ಎರಡೂ ಷರತ್ತುಗಳನ್ನು "ಕೇಸ್ ಅಡಿಯಲ್ಲಿ ತಳ್ಳೋಣ":

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

ಕಾಮೆಂಟ್ ಅನ್ನು ಸೇರಿಸಿ