Как выбрать без ошибки, если таблица не существует - PullRequest
2 голосов
/ 19 января 2020

Я хотел бы запустить SELECT из заданной таблицы, которая не должна завершиться ошибкой, если таблица не существует. Скажем для простоты, что таблица содержит только один столбец и одну строку, и я за этим скаляром. Если таблица не существует, я хочу вернуться 0.

Я знаю, что мог бы сделать что-то вроде:

query("select count(1) from information_schema.tables where table_name = 'versions'")
if result > 0
  return query("select version from versions limit 1")
else
  return 0

Или я мог бы сделать эквивалент, используя хранимую процедуру / plpg sql function.

Но есть ли способ сделать то же самое в одном ad-ho c запросе?

(я делаю два запроса. Я не У меня есть веская причина изменить это. Мне просто любопытно, возможно ли это сделать.)

Ответы [ 2 ]

2 голосов
/ 20 января 2020

Вы хотите одну поездку на сервер с чистым решением SQL. За эти годы было много связанных запросов. Это невозможно в принципе .

  • Вы либо нуждаетесь в Dynami c SQL - для этого требуется функция с использованием PL / pg SQL или другой PL.
  • или вам нужно две поездки в оба конца на сервер. Сначала проверьте существование, затем запрос.

Вы также не можете вложить это в простую функцию SQL, которая будет планировать каждый оператор в теле перед выполнением и завершаться неудачей при попытке разрешить несуществующее имя таблицы. Он даже не прошел бы поверхностные тесты во время создания функции. См .:

Два простых решения для вашего простого случая (среди многих возможных способов):

CREATE OR REPLACE FUNCTION f_select_version_if_exists1() 
  RETURNS int LANGUAGE plpgsql PARALLEL SAFE AS 
$func$
BEGIN 
   IF EXISTS (
      SELECT FROM pg_catalog.pg_tables
      WHERE  tablename  = 'versions'
      AND    schemaname = 'public'  -- see below!
      ) THEN
      RETURN (SELECT version FROM versions LIMIT 1);
   ELSE
      RETURN 0;
   END IF;
END 
$func$;

Или:

CREATE OR REPLACE FUNCTION f_select_version_if_exists2(INOUT _version int = 0) AS 
$func$
BEGIN 
   IF EXISTS (
      SELECT FROM pg_catalog.pg_tables
      WHERE  tablename  = 'versions'
      AND    schemaname = 'public'  -- see below!
      ) THEN
      SELECT INTO _version version
      FROM   versions LIMIT 1;
   END IF;
END 
$func$  LANGUAGE plpgsql PARALLEL SAFE;

Я настоятельно рекомендую также закрепить имя схемы. Имена таблиц не уникальны в Postgres. См .:

Также я сделал функцию PARALLEL SAFE (что имеет значение, только если оно может быть вложено в больших запросов). Это было бы неправильно при использовании search_path, потому что обычно оно включает схему для временных объектов, что делает ее PARALLEL UNSAFE

Второй творчески использует INOUT параметр. Связанный:

0 голосов
/ 19 января 2020

Я считаю, что вам нужна короткая функция PLpg / SQL. Вы можете проверить, существует ли таблица в information_schema.tables, как вы это делали, и сохранить этот результат в переменной. После этого вы можете оценить набор результатов в операторе IF и вернуть все, что хотите, например,

CREATE OR REPLACE FUNCTION f(p_table_name TEXT) 
  RETURNS INT 
LANGUAGE plpgsql AS 
$BODY$
DECLARE 
  res INT;
BEGIN 
  SELECT count(*) 
     into res
  FROM information_schema.tables 
  WHERE table_name = p_table_name;

  IF res>0 THEN RETURN res;
  ELSE RETURN 0;
  END IF;
END 
$BODY$;

Несуществующая таблица

SELECT * FROM f('versions');
 f 
---
 0
(1 Zeile)

Существующая таблица

SELECT * FROM f('t');
 f 
---
 1
(1 Zeile)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...