Я использую следующий скрипт для создания функции

CREATE OR REPLACE FUNCTION public.fninsertreceipttransaction(
accountid1 integer,
customerid1 integer,
receiptid1 integer,
retailerid1 integer,
planid1 integer,
enteredat1 timestamp without time zone,
cardtype1 character varying,
last4digits1 integer,
receiptnumber1 character varying,
totalreceiptspend1 double precision,
transactiondate1 timestamp without time zone,
storeid1 integer,
title1 character varying,
message1 character varying,
enteredby1 character varying)
RETURNS typcounter
LANGUAGE 'plpgsql'
COST 100
VOLATILE 
AS $BODY$

declare 
    counter typcounter;
    planId1 int;
    cardid1 int;
    spendtargetmax1 double precision;
begin

-- insert receipt data
update tblreceipts
set

   ReceiptIssuedAt = transactiondate1,
    IsDownloaded = 't',
    IsProcessed  = 't',
    IsVerified1  = 't',
    IsVerified2  = 't',
    DownloadedAt = current_timestamp,
    ProcessedAt = current_timestamp,
    VerifiedAt1 = current_timestamp,
    VerifiedAt2 = current_timestamp,
    DownloadedBy = 'user1',
    ProcessedBy = 'user1',
    VerifiedBy1 = 'user1',
    VerifiedBy2 = 'user1'
where accountId = accountId1 and receiptId = receiptId1;

-- Check if there is active plan
-- when changing plan status, update actualCompletion date
-- Also update EOD process to include receipts
-- this should change depending on plan start and end condition

-- add transaction
select cardid into cardid1 from TblAccountCards 
    where accountid=accountid1
    and cardtype=cardtype1
    and last4digits=last4digits1;

update TblTransactions
set
    RetailerId = retailerId1,
    StoreId = storeid1,
    TransactionAt = transactiondate1,
    EnteredAt = enteredat1,
    UpdatedAt = current_timestamp,
    Subtotal = totalreceiptspend1,
    CardId =  cardid1
where accountId = accountId1 and receiptId = receiptId1;

-- roll up transactions to plan spent
update tblcustomerplans
set currentAmountSpent = (select sum(subtotal) from TblTransactions where 
                          accountId = accountId1 and planId = planId1)
where 
    accountId = accountId1 
    and customerId = customerId1;

select spendtargetmax into spendtargetmax1 from tblcustomerplans 
    where accountid=accountid1
    and customerid=customerid1
    and planid=planid1;

update tblcustomerplans
set status = 'MarkComplete'
where 
    accountId = accountId1 
    and customerId = customerId1
    and planId = planId1
    and currentamountspent >= spendtargetmax1;

select cast(1 as bigint) into counter;
return counter;
end

$BODY$;

И выполнение функции со следующим запросом

DO $$ BEGIN
PERFORM fninsertreceipttransaction(31, 24, 56, 10001, 53, '2018-11-16 20:03:28', 'Mastercard', '3434', '203', 200, '2018-11-17 00:00:00', 1,
                                          'Receipt Trnasaction', 'Transaction Successfully Processed', 'Admin');

END $$;

Получение ошибки:

ОШИБКА: функция fninsertreceipttransaction (integer, integer, integer, integer, integer, unknown, unknown, unknown, unknown, integer, unknown, integer, unknown, unknown, unknown) не уникальна

Я также отследил все запросы, используя статические данные

                --------------------------------                          
update tblreceipts
set

   ReceiptIssuedAt = '2018-11-17 00:00:00',
    IsDownloaded = 't',
    IsProcessed  = 't',
    IsVerified1  = 't',
    IsVerified2  = 't',
    DownloadedAt = current_timestamp,
    ProcessedAt = current_timestamp,
    VerifiedAt1 = current_timestamp,
    VerifiedAt2 = current_timestamp,
    DownloadedBy = 'user1',
    ProcessedBy = 'user1',
    VerifiedBy1 = 'user1',
    VerifiedBy2 = 'user1'
where accountId = 31 and receiptId = 53;
------------------------------------
select cardid from TblAccountCards 
    where accountid=31
    and cardtype='Mastercard'
    and last4digits=3434;
    ---------------------------------------
    update TblTransactions
set
    RetailerId = 10001,
    StoreId = 1,
    TransactionAt = '2018-11-17 00:00:00',
    EnteredAt = '2018-11-16 20:03:28',
    UpdatedAt = current_timestamp,
    Subtotal = 200,
    CardId =  1
where accountId = 31 and receiptId = 53;
--------------------------------------------
update tblcustomerplans
set currentAmountSpent = (select sum(subtotal) from TblTransactions where 
                          accountId = 31 and planId = 53)
where 
    accountId = 31 and customerId = 24;
------------------------------------------------------------------------
select spendtargetmax from tblcustomerplans 
    where accountid=31 and customerid=24 and planid=53;
   -------------------------------- 
update tblcustomerplans
set status = 'MarkComplete'
 where 
    accountId = 31 
    and customerId = 24
    and planId = 53
    and currentamountspent >= 550;

Но не знаю, почему проблема возникает при выполнении функции

2
Manraj 17 Ноя 2018 в 11:08

1 ответ

Лучший ответ

Это происходит из-за того, что у вас уже есть две или более функции с именем fninsertreceipttransaction и тем же числом аргументов, которые были переданы во время выполнения, и Postgres не может определить, какую из них следует вызвать.

Для иллюстрации создадим 2 функции.

Функция1

knayak= CREATE FUNCTION myfunction(p TIMESTAMP)
knayak- RETURNS BOOLEAN AS $$
knayak$ BEGIN
knayak$         RETURN true;
knayak$ END;
knayak$ $$  LANGUAGE plpgsql;
CREATE FUNCTION

функция2

knayak=
knayak=
knayak= CREATE FUNCTION myfunction(p ) --unknown type p
knayak- RETURNS INTEGER AS $$
knayak$ BEGIN
knayak$         RETURN 1;
knayak$ END;
knayak$ $$  LANGUAGE plpgsql;
CREATE FUNCTION

Теперь попробуйте выполнить функцию, передав строку

knayak= DO $$
knayak$ BEGIN
knayak$  PERFORM myfunction('2018-11-16 20:03:28');
knayak$ END$$;

Я получаю эту ошибку, потому что Postgres не может выбрать между ними на основе моих аргументов.

ОШИБКА: функция myfunction (unknown) не уникальна. СТРОКА 1: SELECT myfunction ('2018-11-16 20:03:28') ^ ПОДСКАЗКА: Не удалось выбрать наилучшую функцию-кандидат. Возможно, вам потребуется добавить явное приведение типов. ЗАПРОС: ВЫБРАТЬ myfunction ('2018-11-16 20:03:28') КОНТЕКСТ: PL / pgSQL функция inline_code_block строка 3 при ВЫПОЛНЕНИИ

Теперь, как узнать, какие функции присутствуют?

Если вы используете командную строку psql , выполните эту простую команду.

knayak=# \df myfunction
                                List of functions
 Schema |    Name    | Result data type |      Argument data types      |  Type
--------+------------+------------------+-------------------------------+--------
 public | myfunction | integer          | p                             | normal
 public | myfunction | boolean          | p timestamp without time zone | normal
(2 rows)

Вы можете видеть, что есть две функции с разными аргументами.

Если вы используете PgAdmin , выполнение этого запроса должно дать вам тот же результат.

SELECT n.nspname as "Schema",
  p.proname as "Name",
  pg_catalog.pg_get_function_result(p.oid) as "Result data type",
  pg_catalog.pg_get_function_arguments(p.oid) as "Argument data types",
 CASE
  WHEN p.proisagg THEN 'agg'
  WHEN p.proiswindow THEN 'window'
  WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN 'trigger'
  ELSE 'normal'
 END as "Type"
FROM pg_catalog.pg_proc p
     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
WHERE p.proname OPERATOR(pg_catalog.~) '^(myfunction)$'
  AND pg_catalog.pg_function_is_visible(p.oid)
ORDER BY 1, 2, 4;

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

Вы не можете просто выдать DROP function <functionname>, который в таких случаях не работает. Вам нужно будет указать подпись аргумента.

knayak=# DROP function myfunction; --Doesn't work
ERROR:  function name "myfunction" is not unique
HINT:  Specify the argument list to select the function unambiguously.

Эти постановления работают.

knayak=#
knayak=# DROP function myfunction(p);
DROP FUNCTION

knayak=# DROP function myfunction(timestamp);
DROP FUNCTION

После сброса повторно запустите скрипт create function только один раз. Он должен работать нормально.

2
Kaushik Nayak 17 Ноя 2018 в 10:40