Функции с переменным количеством входных параметров

Я создаю хранимую процедуру (функцию) в базе данных PostgreSQL, которая обновляет таблицу в зависимости от ее ввода. Чтобы создать переменное число функции параметра, я создаю дополнительный входной параметр, называемый режимом, который я использую для управления параметрами, которые я использую в запросе обновления.

CREATE OR REPLACE FUNCTION update_site( mode integer, name character varying, city character varying, telephone integer, ) RETURNS integer AS $$ BEGIN IF mode = 0 THEN BEGIN UPDATE "Sites" SET ("City","Telephone") = (city,telephone) WHERE "SiteName" = name; RETURN 1; EXCEPTION WHEN others THEN RAISE NOTICE 'Error on site update: %, %',SQLERRM,SQLSTATE; RETURN 0; END; ELSIF mode = 1 THEN BEGIN UPDATE "Sites" SET "City" = city WHERE "SiteName" = name; RETURN 1; EXCEPTION WHEN others THEN RAISE NOTICE 'Error on site update: %, %',SQLERRM,SQLSTATE; RETURN 0; END; ELSIF mode = 2 THEN BEGIN UPDATE "Sites" SET "Telephone" = telephone WHERE "SiteName" = name; RETURN 1; EXCEPTION WHEN others THEN RAISE NOTICE 'Error on site update: %, %',SQLERRM,SQLSTATE; RETURN 0; END; ELSE RAISE NOTICE 'Error on site update: %, %',SQLERRM,SQLSTATE; RETURN 0; END IF; END; $$ LANGUAGE plpgsql; 

Что было бы лучше? Чтобы создать функцию update_site(<all the columns of table>) и отдельную функцию update_site(id integer, <varchar column to update>) или использовать режим в одной функции, чтобы определить разницу? Какой вариант более эффективен? Одна уникальная функция или разные для каждой цели?

Расширенные функции, такие как VARIADIC или даже полиморфные типы ввода и динамический SQL, очень эффективны. Последняя глава этого ответа содержит расширенный пример:
Рефакторинг функции PL / pgSQL для возврата результатов различных запросов SELECT

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

 CREATE OR REPLACE FUNCTION update_site( _name text -- always required, so no default , _city text DEFAULT NULL , _telephone integer DEFAULT NULL) RETURNS integer AS $func$ BEGIN IF _city IS NULL AND _telephone IS NULL THEN RAISE WARNING 'At least one value to update required!'; RETURN; -- nothing to update END IF; UPDATE "Sites" SET "City" = COALESCE(_city, "City") SET "Telephone" = COALESCE(_telephone, "Telephone") WHERE "SiteName" = _name; END $func$ LANGUAGE plpgsql; 

Обязательно прочтите информацию о значениях по умолчанию в руководстве !

Чтобы избежать именования конфликтов между параметрами и именами столбцов, я делаю привычкой префикс входных параметров с помощью _ . Это вопрос вкуса и стиля.

  • Первое name параметра не имеет значения по умолчанию, так как оно требуется всегда.
  • Другие параметры могут быть заданы или нет.
  • Требуется хотя бы один, или WARNING поднимается, и больше ничего не происходит.
  • UPDATE будет изменять только столбцы для заданных параметров.
  • Легко можно разложить на n параметров.

Вызов

Вы можете назвать это традиционным способом, с позиционной обозначением параметров. Это позволяет вам опустить самый правый параметр (ы):

 SELECT update_site('foo', 'New York') -- no telephone 

Чтобы упустить любой параметр со значением по умолчанию, вам нужно использовать именованное обозначение в вызове:

 SELECT update_site(name := 'foo', _telephone := 123); -- no city 

Или, чтобы упростить еще больше, вы можете использовать смешанные обозначения :

 SELECT update_site('foo', _telephone := 123); 

Есть несколько вещей, которые вы захотите изучить:

  • Динамическое построение SQL с использованием функции format и спецификаторов %I и %L , затем выполнение ее с помощью EXECUTE ... USING ; а также

  • Используя параметры VARIADIC чтобы принимать переменные числа аргументов функции, с оговоркой, что все они должны быть одного и того же типа данных.