Есть ли альтернатива «SELECT INTO» в «IF EXISTS (...)»? - PullRequest
0 голосов
/ 20 февраля 2020

Итак, я пытаюсь написать проверку целостности.

Foo s имеет Top s и либо Alpha xor a Beta.

Top , Alpha и Beta все ссылки Gamma и в зависимости от того, Alpha или Beta a Foo должен ссылаться на тот же Gamma, что и его Top.

т.е.

foo1 --> top1 --> gamma1
foo1 --> alpha1 --> gamma1

разрешено,

foo1 --> top1 --> gamma1
foo1 --> alpha1 --> gamma2

запрещено

Я пытался

DO $check$
DECLARE
   violation_type TEXT;
BEGIN
   IF EXISTS(
       SELECT CASE WHEN alpha.id IS NOT NULL THEN 'alpha' ELSE 'beta' END INTO violation_type
       FROM
           Foo o
           LEFT JOIN top t ON o.top_id = t.id
           LEFT JOIN alpha a ON o.alpha_id = a.id
           LEFT JOIN beta b ON o.beta_id = b.id
       WHERE
           t.gamma_id <> coalesce(a.gamma_id, b.gamma_id)
   )THEN
       RAISE EXCEPTION 'Foo Violation: There are %-type foos whose top references a different gamma', violation_type;
   END IF;
END $check$;

Но это не удается, потому что

ОШИБКА: ВЫБРАТЬ ... INTO здесь не разрешено

Это позор, потому что я бы очень предпочел не дублировать этот код, просто проверить один раз на Alpha и один раз для Beta.

Есть ли альтернатива, которую можно использовать здесь, или я застрял с двумя проверками?

1 Ответ

3 голосов
/ 21 февраля 2020

Вы не можете использовать SELECT INTO в подзапросе EXISTS. Руководство :

Как правило, подзапрос будет выполняться достаточно долго, чтобы определить, возвращена ли хотя бы одна строка, а не весь путь до завершения.

Вместо этого используйте SELECT INTO и проверьте с помощью IF FOUND ... на следующем шаге:

DO
$check$
DECLARE
   violation_type TEXT;
BEGIN
   SELECT INTO violation_type
   CASE   WHEN f.alpha.id IS NOT NULL THEN 'alpha' ELSE 'beta' END
   FROM   foo        f
   JOIN   top        t ON t.id = f.top_id
   LEFT   JOIN alpha a ON a.id = f.alpha_id
   LEFT   JOIN beta  b ON b.id = f.beta_id
   WHERE  t.gamma_id <> coalesce(a.gamma_id, b.gamma_id);

   -- IF violation_type IS NOT NULL THEN  -- alternative
   IF FOUND THEN
      RAISE EXCEPTION 'Foo Violation: There are %-type foos whose top references a different gamma', violation_type;
   END IF;
END
$check$;

В качестве альтернативы, вы можете проверить, была ли назначена переменная, как показано с комментарием.

...