Элегантный способ обработки исключений 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.
дополнительная информация:
руководство о том, как ловить ошибки (обрабатывать исключения) в PL/pgSQL
пример: является ли SELECT или INSERT функцией, склонной к условиям гонки?
как избежать исключение в пример
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
Если вам требуется больше строк, вам может потребоваться создать функцию с типами.