Есть ли способ получить более значимое сообщение об ошибке в postgres? - PullRequest
0 голосов
/ 10 января 2020

Давайте выпьем чаю ...

CREATE OR REPLACE FUNCTION allRelevantTeas() RETURNS TABLE(tea_id INTEGER) AS $function$
DECLARE
    result REFCURSOR;
    stmt TEXT;
    countries_with_tea TEXT[] := array['england', 'turkey', 'india', 'japan', 'china'];
BEGIN
    stmt := '';
    FOR tea_drinker in countries_with_tea LOOP
        stmt := stmt || format($$(SELECT tea_id FROM %I)$$, tea_drinker);
        IF tea_drinker <> 'china' THEN
            stmt := stmt || $$ UNION $$;
        END IF;
    END LOOP;

    OPEN result FOR EXECUTE stmt;
    RETURN result;
END $function$
LANGUAGE plpgsql STABLE;

SELECT * FROM allRelevantTeas();

Давайте проверим это ...

Синтаксическая ошибка в или рядом с "country_with_tea"

Я не вижу этого. Это, вероятно, совершенно очевидно, но я просто не вижу этого.

Кто-нибудь замечает, что с этим не так? Или, если нет, есть ли способ получить более значимую ошибку из postgres, чем «произошла синтаксическая ошибка (но я не говорю вам, что это было)»?

Ответы [ 3 ]

1 голос
/ 10 января 2020

Просто небольшая заметка. Я часто смотрю на свой код и спрашиваю: «Есть ли что-нибудь, что может быть нарушено при любых предсказуемых изменениях, и могу ли я предотвратить это сейчас?» Это служило мне хорошо в течение многих лет, и я почти всегда могу что-то найти. Здесь есть один. Утверждение «Если tea_drinker ... end if» очень fr agile. Что происходит, когда другая страна добавляется в массив и добавляется после Китая. Ответ, ваш SQL не выполняется при выполнении. Закаленная версия будет проверять позицию текущего tea_drinker до последнего входа в массив. Это можно сделать с помощью функций массива , array_position и array_length.

-- Instead of: 
IF tea_drinker <> 'china' THEN
   stmt := stmt || $$ UNION $$;
END IF;

-- Use 
if array_position(countries_with_tea, tea_drinker) <> array_length(countries_with_tea, 1)
then 
   stmt := stmt || $$ UNION $$;
end if;
1 голос
/ 10 января 2020

Ваш l oop неправильный, вам нужно использовать FOREACH до l oop через элементы массива :

CREATE OR REPLACE FUNCTION allRelevantTeas() RETURNS TABLE(tea_id INTEGER) AS $function$
DECLARE
    stmt TEXT;
    tea_drinker text;
    countries_with_tea TEXT[] := array['england', 'turkey', 'india', 'japan', 'china'];
BEGIN
    stmt := '';
    FOREACH tea_drinker in array countries_with_tea LOOP
        stmt := stmt || format($$(SELECT tea_id FROM %I)$$, tea_drinker);
        IF tea_drinker <> 'china' THEN
            stmt := stmt || $$ UNION $$;
        END IF;
    END LOOP;

    RETURN query execute stmt;
END $function$
LANGUAGE plpgsql STABLE;

Вы не Для действительно необходим UNION, вы можете использовать return query для возврата нескольких результатов:

CREATE OR REPLACE FUNCTION allrelevantteas() 
  RETURNS TABLE(tea_id INTEGER) AS $function$
DECLARE
    stmt TEXT;
    tea_drinker text;
    countries_with_tea TEXT[] := array['england', 'turkey', 'india', 'japan', 'china'];
BEGIN
    stmt := '';
    FOREACH tea_drinker in array countries_with_tea LOOP
      stmt := format($$(SELECT tea_id FROM %I)$$, tea_drinker);
      return query execute stmt;
    END LOOP;
END $function$
LANGUAGE plpgsql STABLE;

Онлайн пример


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

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

a_horse_with_no_name рассказал вам, как исправить ошибку, но для получения более значимого сообщения об ошибке я уже получил его, используя psql:

ERROR:  syntax error at or near "countries_with_tea"
LINE 8:     FOR tea_drinker in countries_with_tea LOOP
                               ^

Если вы видите только первую строку и не следующие два, тогда вы используете какой-то инструмент, который не ваш друг.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...