无法选择最佳候选函数。您可能需要在Postgres中添加显式类型转换

时间:2018-11-17 08:08:56

标签: c# postgresql .net-core npgsql pgadmin

我正在使用以下脚本创建函数

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(整数,整数,整数,   整数,整数,未知,未知,未知,未知,整数,   未知,整数,未知,未知,未知)不是唯一

我还使用静态数据回溯了所有查询

                --------------------------------                          
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;

但是不知道问题为什么会执行功能

1 个答案:

答案 0 :(得分:2)

之所以发生这种情况,是因为您已经创建了两个或多个名称为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)不是唯一的LINE 1:SELECT   myfunction('2018-11-16 20:03:28')                  ^提示:无法选择最佳候选函数。您可能需要添加显式类型转换。查询:选择   myfunction('2018-11-16 20:03:28')上下文:PL / pgSQL函数   inline_code_block在PERFORM的第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脚本一次。它应该可以执行。