Как работают переменные в функциях PL / pg SQL - PullRequest
1 голос
/ 09 июля 2020

Я новичок в функциях plpg sql.

Кто-нибудь может объяснить, как это работает?

CREATE OR REPLACE FUNCTION test1(
    IN a TEXT,
    IN b  TEXT
        )
        RETURNS void AS $func$
        DECLARE
          cnt INT2;
        BEGIN
          SELECT
            COUNT(*)
          INTO STRICT
            cnt
          FROM
            pg_catalog.pg_class
          WHERE 1 = 1
            AND a = $1
            AND b = $2;
        RAISE NOTICE '%', cnt;
        END; $func$
        LANGUAGE plpgsql;

postgres=# SELECT test1('1', '2');
NOTICE:  311
 test1
-------

(1 row)

Почему это вообще работает? У нас нет атрибутов a и b в pg_class? Почему УВЕДОМЛЕНИЕ возвращает результат select * from pg_class?

1 Ответ

1 голос
/ 09 июля 2020

Ну, вы делаете это:

SELECT
    COUNT(*)
FROM
    pg_catalog.pg_class
WHERE 1 = 1
AND '1' = '1'
AND '2' = '2';

count 
-------
   554

и это правда, поэтому вы получите то же самое, что и это:


SELECT
    COUNT(*)
FROM
    pg_catalog.pg_class
;

count 
-------
   554

Если вы хотите, чтобы это не удалось, примите двусмысленность из него:

CREATE OR REPLACE FUNCTION public.test1(a text, b text)
 RETURNS void
 LANGUAGE plpgsql
AS $function$
        DECLARE
          cnt INT2;
        BEGIN
          SELECT
            COUNT(*)
          INTO STRICT
            cnt
          FROM
            pg_catalog.pg_class
          WHERE 1 = 1
            AND pg_catalog.pg_class.a = $1
            AND pg_catalog.pg_class.b = $2;
        RAISE NOTICE '%', cnt;
        END; $function$
;

select test1('1', '2');
ERROR:  column pg_class.a does not exist
LINE 6:             AND pg_catalog.pg_class.a = $1
                        ^
QUERY:  SELECT
            COUNT(*)
                                                FROM
            pg_catalog.pg_class
          WHERE 1 = 1
            AND pg_catalog.pg_class.a = $1
            AND pg_catalog.pg_class.b = $2
CONTEXT:  PL/pgSQL function test1(text,text) line 5 at SQL statement


Для получения дополнительной информации см .:

https://www.postgresql.org/docs/current/plpgsql-implementation.html#PLPGSQL -VAR-SUBST

"Поскольку имена переменных синтаксически не отличается от имен столбцов таблицы, может быть двусмысленность в операторах, которые также относятся к таблицам: данное имя предназначено для ссылки на столбец таблицы или переменную? Давайте изменим предыдущий пример на

INSERT INTO dest (col) SELECT foo + bar FROM src;

Здесь dest и sr c должны быть именами таблиц, а col должно быть столбцом dest, но foo и bar могут быть любыми переменными функции или столбцов sr c.

По умолчанию PL / pg SQL сообщит об ошибке, если имя в операторе SQL может относиться либо к переменной, либо к столбцу таблицы. Вы можете решить эту проблему, переименовав переменную или столбец, или указав неоднозначная ссылка или указание PL / pg SQL, какую интерпретацию предпочесть.

Простейшее решение - переименовать переменную или столбец. Распространенным правилом кодирования является использование другого соглашения об именах для переменных PL / pg SQL, чем для имен столбцов. Например, если вы последовательно называете функциональные переменные v_something, в то время как ни одно из имен столбцов не начинается с v_, конфликтов возникать не будет.

В качестве альтернативы вы можете квалифицировать неоднозначные ссылки, чтобы прояснить их. В приведенном выше примере sr c .foo будет однозначной ссылкой на столбец таблицы. Чтобы создать однозначную ссылку на переменную, объявите ее в помеченном блоке и используйте метку блока (см. Раздел 42.2). Например, ... "

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