PostgreSQL Antipatterns: вычислСниС условий Π² SQL

SQL β€” это Π½Π΅ C++, ΠΈ Π½Π΅ JavaScript. ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ вычислСниС логичСских Π²Ρ‹Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ происходит ΠΈΠ½Π°Ρ‡Π΅, ΠΈ Π²ΠΎΡ‚ это β€” совсСм Π½Π΅ ΠΎΠ΄Π½ΠΎ ΠΈ Ρ‚ΠΎ ΠΆΠ΅:

WHERE fncondX() AND fncondY()

= fncondX() && fncondY()

Π’ процСссС ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΏΠ»Π°Π½Π° исполнСния запроса PostgreSQL ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ»ΡŒΠ½Ρ‹ΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ Β«ΠΏΠ΅Ρ€Π΅ΡΡ‚Π°Π²Π»ΡΡ‚ΡŒΒ» эквивалСнтныС условия, Π½Π΅ Π²Ρ‹Ρ‡ΠΈΡΠ»ΡΡ‚ΡŒ ΠΊΠ°ΠΊΠΈΠ΅-Ρ‚ΠΎ ΠΈΠ· Π½ΠΈΡ… для ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Ρ… записСй, ΠΎΡ‚Π½ΠΎΡΠΈΡ‚ΡŒ ΠΊ ΡƒΡΠ»ΠΎΠ²ΠΈΡŽ примСняСмого индСкса… ΠšΠΎΡ€ΠΎΡ‡Π΅, ΠΏΡ€ΠΎΡ‰Π΅ всСго ΡΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ Π²Ρ‹ Π·Π°Ρ€Π°Π½Π΅Π΅ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ Ρ‚Π΅ΠΌ, Π² ΠΊΠ°ΠΊΠΎΠΌ порядкС Π±ΡƒΠ΄ΡƒΡ‚ (ΠΈ Π±ΡƒΠ΄ΡƒΡ‚ Π»ΠΈ Π²ΠΎΠΎΠ±Ρ‰Π΅) Π²Ρ‹Ρ‡ΠΈΡΠ»ΡΡ‚ΡŒΡΡ Ρ€Π°Π²Π½ΠΎΠΏΡ€Π°Π²Π½Ρ‹Π΅ условия.

ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ Ссли ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚ΠΎΠΌ всС-Ρ‚Π°ΠΊΠΈ хочСтся, Π½Π°Π΄ΠΎ структурно ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ эти условия Π½Π΅Ρ€Π°Π²Π½Ρ‹ΠΌΠΈ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ условных Π²Ρ‹Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ ΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΠ².

PostgreSQL Antipatterns: вычислСниС условий Π² SQL
Π”Π°Π½Π½Ρ‹Π΅ ΠΈ Ρ€Π°Π±ΠΎΡ‚Π° с Π½ΠΈΠΌΠΈ β€” основа нашСго комплСкса Π‘Π‘Π˜Π‘, поэтому Π½Π°ΠΌ ΠΎΡ‡Π΅Π½ΡŒ Π²Π°ΠΆΠ½ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ Π½Π°Π΄ Π½ΠΈΠΌΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΠ»ΠΈΡΡŒ Π½Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½ΠΎ, Π½ΠΎ ΠΈ эффСктивно. Π”Π°Π²Π°ΠΉΡ‚Π΅ посмотрим Π½Π° ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹Ρ… ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°Ρ…, Π³Π΄Π΅ ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ Π΄ΠΎΠΏΡƒΡ‰Π΅Π½Ρ‹ ошибки вычислСния Π²Ρ‹Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ, Π° Π³Π΄Π΅ стоит ΡƒΠ»ΡƒΡ‡ΡˆΠΈΡ‚ΡŒ ΠΈΡ… ΡΡ„Ρ„Π΅ΠΊΡ‚ΠΈΠ²Π½ΠΎΡΡ‚ΡŒ.

#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: OR/AND-Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠ°

SELECT ... WHERE EXISTS(... A) OR EXISTS(... B)

Π’ нСприятном случаС ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ ΠΎΠ±Π° EXISTS Π±ΡƒΠ΄ΡƒΡ‚ «истинными», Π½ΠΎ ΠΎΠ±Π° ΠΈ выполнятся.

Но Ссли ΠΌΡ‹ Ρ‚ΠΎΡ‡Π½ΠΎ Π·Π½Π°Π΅ΠΌ, Ρ‡Ρ‚ΠΎ ΠΎΠ΄ΠΈΠ½ ΠΈΠ· Π½ΠΈΡ… Π±Ρ‹Π²Π°Π΅Ρ‚ «истинным» ΠΌΠ½ΠΎΠ³ΠΎ Ρ‡Π°Ρ‰Π΅ (ΠΈΠ»ΠΈ Β«Π»ΠΎΠΆΠ½Ρ‹ΠΌΒ» β€” для AND-Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠΈ) β€” нСльзя Π»ΠΈ ΠΊΠ°ΠΊ-Ρ‚ΠΎ Β«ΠΏΠΎΠ²Ρ‹ΡΠΈΡ‚ΡŒ Π΅Π³ΠΎ ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚Β», Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²Ρ‚ΠΎΡ€ΠΎΠΉ Π½Π΅ выполнялся лишний Ρ€Π°Π·?

ΠžΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ΡΡ, ΠΌΠΎΠΆΠ½ΠΎ β€” алгоритмичСски ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ Π±Π»ΠΈΠ·ΠΎΠΊ ΠΊ Ρ‚Π΅ΠΌΠ΅ ΡΡ‚Π°Ρ‚ΡŒΠΈ PostgreSQL Antipatterns: рСдкая запись Π΄ΠΎΠ»Π΅Ρ‚ΠΈΡ‚ Π΄ΠΎ сСрСдины JOIN.

Π”Π°Π²Π°ΠΉΡ‚Π΅ просто «засунСм ΠΏΠΎΠ΄ CASEΒ» ΠΎΠ±Π° эти условия:

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: ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚Π΅Ρ‚ bool-ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ

ΠžΡ‚Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ΠΈΡ€ΡƒΠ΅ΠΌ исходник:

{... IS NULL} OR
{... ΠšΠΎΠΌΠΏΠ»Π΅ΠΊΡ‚} OR
{... Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ΠŸΠΎΠ—Π°Ρ€ΠΏΠ»Π°Ρ‚Π΅} AND
( {... нСравСнства} )

Упс… По Ρ„Π°ΠΊΡ‚Ρƒ, ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΎΡΡŒ, Ρ‡Ρ‚ΠΎ Π² случаС истинности любого ΠΈΠ· Π΄Π²ΡƒΡ… ΠΏΠ΅Ρ€Π²Ρ‹Ρ… условий, всС условиС Ρ†Π΅Π»ΠΈΠΊΠΎΠΌ обращаСтся Π² TRUE, Π±Π΅Π· ΡƒΡ‡Π΅Ρ‚Π° нСравСнств. А это совсСм Π½Π΅ Ρ‚ΠΎ, Ρ‡Π΅Π³ΠΎ ΠΌΡ‹ Ρ…ΠΎΡ‚Π΅Π»ΠΈ.

Π˜ΡΠΏΡ€Π°Π²ΠΈΠΌ:

(
  {... IS NULL} OR
  {... ΠšΠΎΠΌΠΏΠ»Π΅ΠΊΡ‚} OR
  {... Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ΠŸΠΎΠ—Π°Ρ€ΠΏΠ»Π°Ρ‚Π΅}
) AND
( {... нСравСнства} )

ΠŸΡ€ΠΎΠ±Π»Π΅ΠΌΠ° β„–4 (малСнькая): слоТноС OR-условиС для ΠΎΠ΄Π½ΠΎΠ³ΠΎ поля

БобствСнно, ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ Π² β„–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…

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com

Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ