如何将数组或列表传递给 PostgreSQL 中的存储过程

How to pass an array or list to a stored procedure in PostgreSQL

我正在尝试在 PostgreSQL 中开发一个存储的 procedure/function 来接受和处理来自 SSRS 的列表。我在将列表传递给存储过程时遇到了一些问题。这是查询

CREATE OR REPLACE FUNCTION get_transaction_all_accounts(p_property[] varchar, p_year timestamp without time zone)
 RETURNS record
 LANGUAGE plpgsql
AS $function$
DECLARE
  l_num_property numeric(15,2);
  l_num_amount numeric(15,2);
  l_property   varchar   := '';
  l_year    timestamp := LOCALTIMESTAMP;
  result RECORD;
BEGIN
  IF ( p_property IS NOT NULL ) THEN
    l_property := p_property;
  END IF;
  IF ( p_year IS NOT NULL ) THEN
    l_year := p_year;
  END IF;
  SELECT INTO l_num_property, l_num_amount 
  property::numeric(15,2), coalesce(sum(amount),0)::numeric(15,2) from (
    select a.propertyname AS property, a.amount 
    FROM sw."fTransaction" a
    WHERE a.propertyname = l_property
  )as foo;
  SELECT INTO result l_num_property, l_num_amount;
  RETURN result;
END;
$function$
;

-- Permissions

ALTER FUNCTION get_transaction_all_accounts(varchar,timestamp) OWNER TO myuser;
GRANT ALL ON FUNCTION get_transaction_all_accounts(varchar,timestamp) TO myuser;

这里是数据集查询

select sum(amount) as sink from get_transaction_all_accounts(?,?, -1)  as ("property" numeric, "amount" numeric)

我使用的参数表达式:

Join(Parameters!property.Value,",")
DateAdd("d", 1, Parameters!date.Value)

我不知道如何处理将列表数据传递给函数参数的查询。请帮我做这个

谢谢

使用逗号分隔的输入值和其他值的函数,并准备动态查询,其中输入参数很少(如果提供),并使用 regexp_split_to_table 将逗号分隔的值拆分为列表。如果 null 或空字符串 ('') 用作输入值,则相关列名称不用于搜索条件。

-- PostgreSQL (v14)
-- Function: public.rpt_member_info(character varying, character varying, character varying, character varying, character varying)

DROP FUNCTION IF EXISTS public.rpt_member_info(character varying, character varying, character varying, character varying, character varying);

CREATE OR REPLACE FUNCTION public.rpt_member_info(
    IN p_officeInfoId CHARACTER VARYING,
    IN p_projectInfoId CHARACTER VARYING,
    IN p_memberInfoId CHARACTER VARYING,
    IN p_fromDate CHARACTER VARYING,
    IN p_toDate CHARACTER VARYING,
    OUT member_id BIGINT,
    out office_info_id bigint,
    out project_info_id bigint,
    OUT member_no CHARACTER VARYING,
    OUT member_name CHARACTER VARYING,
    OUT membership_date TIMESTAMP WITHOUT TIME ZONE)
  RETURNS SETOF record AS
$BODY$

-- declare local variables
DECLARE v_prepareQuery         VARCHAR(21840) DEFAULT '';
    v_officeInfo           VARCHAR(150) DEFAULT '';
    v_projectInfo          VARCHAR(150) DEFAULT '';
    v_memberInfo           VARCHAR(150) DEFAULT '';
    refcur refcursor default 'test';

BEGIN
    
    /**************************History**************************/
    -- Name : rpt_member_info
    -- Created Date (dd/MM/yyyy): 01/02/2022 
    -- Created By : Rahul Biswas
    -- Reason : 
    -- Execute : SELECT * FROM rpt_member_info('101', '1', '1', '2022-01-01', '2022-01-31');
    /***********************************************************/

    -- prepare variable data based on given input
    IF(p_officeInfoId != '' AND p_officeInfoId != 'null' AND p_officeInfoId IS NOT NULL)
    THEN
        v_officeInfo = CONCAT(' AND mi.office_info_id = ANY(SELECT CAST(regexp_split_to_table(''', p_officeInfoId, ''',''', ', '') AS BIGINT))', CHR(10));
    END IF;

    IF(p_projectInfoId != '' AND p_projectInfoId != 'null' AND p_projectInfoId IS NOT NULL)
    THEN
        v_projectInfo = CONCAT(' AND mi.project_info_id = ', p_projectInfoId, CHR(10));
    END IF;

    IF(p_memberInfoId != '' AND p_memberInfoId != 'null' AND p_memberInfoId IS NOT NULL)
    THEN
        v_memberInfo = CONCAT(' AND mi.id = ', p_memberInfoId, CHR(10));
    END IF;

    -- prepare query
        v_prepareQuery := CONCAT('SELECT mi.id member_id
                                       , mi.office_info_id
                                       , mi.project_info_id
                                       , mi.member_no
                                       , mi.member_name
                                       , mi.membership_date
                                  FROM member_info mi
                                  WHERE 1 = 1', CHR(10)
                                  , v_officeInfo
                                  , v_projectInfo
                                  , v_memberInfo
                                  , 'AND mi.membership_date BETWEEN ', '''', p_fromDate, '''', ' AND ', '''', p_toDate, '''', ';');
 
 RETURN QUERY EXECUTE v_prepareQuery;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE;

执行这个函数

SELECT * FROM rpt_member_info('101, 102', '1', '', '2022-01-01', '2022-01-31');

请检查这个urlhttps://dbfiddle.uk/?rdbms=postgres_14&fiddle=a38347cb181d0347a06ba6304e9448ef

如果不使用动态查询并提供逗号分隔值作为输入,则使用以下函数

-- Function: public.rpt_member_info(character varying, bigint, TIMESTAMP WITHOUT TIME ZONE, bigint, TIMESTAMP WITHOUT TIME ZONE, TIMESTAMP WITHOUT TIME ZONE)

DROP FUNCTION IF EXISTS public.rpt_member_info(character varying, bigint, TIMESTAMP WITHOUT TIME ZONE, TIMESTAMP WITHOUT TIME ZONE);

CREATE OR REPLACE FUNCTION public.rpt_member_info(
    IN p_officeInfoId CHARACTER VARYING,
    IN p_projectInfoId BIGINT,
    IN p_fromDate TIMESTAMP WITHOUT TIME ZONE,
    IN p_toDate TIMESTAMP WITHOUT TIME ZONE,
    OUT member_id BIGINT,
    out office_info_id bigint,
    out project_info_id bigint,
    OUT member_no CHARACTER VARYING,
    OUT member_name CHARACTER VARYING,
    OUT membership_date TIMESTAMP WITHOUT TIME ZONE)
  RETURNS SETOF record AS
$BODY$

-- declare local variables
DECLARE v_prepareQuery         VARCHAR(21840) DEFAULT '';
    v_officeInfo           VARCHAR(150) DEFAULT '';
    v_projectInfo          VARCHAR(150) DEFAULT '';
    v_memberInfo           VARCHAR(150) DEFAULT '';
    refcur refcursor default 'test';

BEGIN
    
    /**************************History**************************/
    -- Name : rpt_member_info
    -- Created Date (dd/MM/yyyy): 01/02/2022 
    -- Created By : Rahul Biswas
    -- Reason : 
    -- Execute : SELECT * FROM rpt_member_info('101, 102', 1, '2022-01-01', '2022-01-31');
    /***********************************************************/

    -- execute query
        RETURN QUERY SELECT mi.id member_id
                                  , mi.office_info_id
                                  , mi.project_info_id
                                  , mi.member_no
                                  , mi.member_name
                                  , mi.membership_date
                             FROM member_info mi
                             WHERE mi.office_info_id = ANY(SELECT CAST(regexp_split_to_table(p_officeInfoId, ',') AS BIGINT))
                                  AND mi.project_info_id = p_projectInfoId
                                  AND mi.membership_date BETWEEN p_fromDate AND p_toDate;
 
 
END;
$BODY$
  LANGUAGE plpgsql VOLATILE;

执行函数

SELECT * FROM rpt_member_info('101, 102', 1, '2022-01-01', '2022-01-31');

请用这个urlhttps://dbfiddle.uk/?rdbms=postgres_14&fiddle=ee5b70bbb8fbeacbb9fad280cc775b58

N.B.: 在较低版本的 Postgresql 中,函数和存储过程的行为相同。