Элегантный способ обработки исключений PostgreSQL?

в PostgreSQL я хотел бы создать механизм безопасной упаковки, который возвращает пустой результат, если происходит исключение. Рассмотрим следующее:

SELECT * FROM myschema.mytable;

Я мог бы сделать безопасную обертку в клиентском приложении:

try {
    result = execute_query('SELECT value FROM myschema.mytable').fetchall();
}
catch(pg_exception) {
    result = []
}

но могу ли я сделать такую вещь в SQL напрямую? Я хотел бы, чтобы следующий код работал, но, похоже, он должен быть помещен в DO $$ ... $$ блок и здесь я теряюсь.

BEGIN
    SELECT * FROM myschema.mytable;
EXCEPTION WHEN others THEN
    SELECT unnest(ARRAY[]::TEXT[])
END

2 ответов


обработка исключений в PL/pgSQL

как правило, код plpgsql всегда завернут в BEGIN .. END блок. Это может быть внутри тела DO оператор или функция. Блоки могут быть вложены внутрь-но они не могут существовать за пределами, не путайте это с простым SQL.

каждого BEGIN блок может дополнительно включать в себя EXCEPTION предложение для обработки исключений, но функции, которые должны ловить исключения, значительно дороже, поэтому лучше избегать исключений a priori.

дополнительная информация:

как избежать исключение в пример

A DO оператор ничего не может вернуть. создать функции, которая принимает имя таблицы и схемы в качестве параметров и возвращает все, что вы хотите:

CREATE OR REPLACE FUNCTION f_tbl_value(_tbl text, _schema text = 'public')
  RETURNS TABLE (value text) AS
$func$
DECLARE
   _t regclass := to_regclass(_schema || '.' || _tbl);
BEGIN
   IF _t IS NULL THEN
      value := ''; RETURN NEXT;    -- return single empty string
   ELSE
      RETURN QUERY EXECUTE
      'SELECT value FROM ' || _t;  -- return set of values
   END
$func$ LANGUAGE plpgsql;

звоните:

SELECT * FROM f_tbl_value('my_table');

или:

SELECT * FROM f_tbl_value('my_table', 'my_schema');
  • предполагая, что вы хотите набор строк с одним text столбец или пустая строка, если таблица не существует.

  • также предполагая, что столбец value существует, если данная таблица существует. Вы могли бы проверить и это, но вы не просили об этом.

  • оба параметра регистр text значения. Это тонко отличается от how идентификаторы в операторах SQL обрабатываются. Если вы никогда не указываете идентификаторы с двойной кавычкой, передайте имена в нижнем регистре, и все в порядке.

  • имя схемы по умолчанию 'public' в моем примере. Приспособьтесь к вашему по необходимости. Вы даже можете полностью игнорировать схему и по умолчанию использовать текущий search_path.

  • to_regclass() является новым в Postgres 9.4. Для более старых версий замените:

    IF EXISTS (
       SELECT 1
       FROM   information_schema.tables 
       WHERE  table_schema = _schema
       AND    table_name = _tbl
    );
    

    это на самом деле точнее, потому что он проверяет именно то, что вам нужно. Дополнительные опции и подробное объяснение:

  • всегда защищайтесь от SQL-инъекций при работе с динамическим SQL! Бросок в regclass здесь делает трюк. Более детально:


Если вы выбираете только один столбец, то функция COALESCE () должна быть в состоянии сделать трюк для вас

SELECT COALESCE( value, '{}'::text[] ) FROM myschema.mytable

Если вам требуется больше строк, вам может потребоваться создать функцию с типами.