plpgsql 函数 concat 可选参数 返回错误

Posted

技术标签:

【中文标题】plpgsql 函数 concat 可选参数 返回错误【英文标题】:plpgsql function concat optionnal args return error 【发布时间】:2020-05-06 08:41:09 【问题描述】:

我想连接由 AND 分隔的可选参数,并返回那些非空的连接参数的 varchar。

CREATE OR REPLACE FUNCTION shop_apply_search_filters(price_min INTEGER DEFAULT NULL, price_max INTEGER DEFAULT NULL, ecom_id  INTEGER DEFAULT NULL, 
                                                        cat_1 VARCHAR DEFAULT NULL, cat_2 VARCHAR DEFAULT NULL)
  RETURNS VARCHAR AS
$$
DECLARE final_filters VARCHAR(500);
BEGIN
    IF price_min IS NOT NULL THEN
        SELECT CONCAT('price<',price_min) AS n_price_min;
        final_filters := n_price_min;
    END IF;

    IF price_max IS NOT NULL THEN
        SELECT CONCAT('price>',price_max) AS n_price_max;
        final_filters := CONCAT(final_filters,' AND ', n_price_max);
    END IF;

    IF ecom_id IS NOT NULL THEN
        SELECT CONCAT('ecom_id=',ecom_id) AS n_ecom_id;
        final_filters := CONCAT(final_filters,' AND ', n_ecom_id);
    END IF;

    IF cat_1 IS NOT NULL THEN
        SELECT CONCAT('category_1:',cat_1) AS n_cat_1;
        final_filters := CONCAT(final_filters,' AND ', n_cat_1);
    END IF;

    IF cat_2 IS NOT NULL THEN
        SELECT CONCAT('category_2:',cat_2) AS n_cat_2;
        final_filters := CONCAT(final_filters,' AND ', n_cat_2);
    END IF;

    RETURN final_filters;
END;
$$
LANGUAGE PLPGSQL;

SELECT shop_apply_search_filters(10) 的输出将是一个类似于“价格 > 10”的字符串。 调用函数时是否可以传递参数名称?为了能够区分 price_min 和 price_max 如果只通过其中一个。 是否可以将非空参数附加到列表中,然后使用 AND 加入列表元素?

你会怎么做?

编辑

我在 CONCAT() 时删除了 SELECT() 以避免错误。但我有一个新的:

ERROR:  query has no destination for result data
HINT:  If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT:  PL/pgSQL function shop_apply_search_filters(integer,integer,integer,character varying,character varying) line 5 at SQL statement
SQL state: 42601

编辑 我试过了:

create or replace function shop_apply_search_filters(
    price_min integer default null, 
    price_max integer default null, 
    ecom_id  integer default null, 
    cat_1 text default null, 
    cat_2 text default null)
returns text as
$$
    select concat_ws(
        ' and ',
        'price < '      || price_min,
        'price > '      || price_max,
        'ecom_id = '    || ecom_id,
        'category_1 = ' || cat_1,
        'category_2 = ' || cat_2
    );
$$
language sql;

它适用于所有传递的参数:

SELECT shop_apply_search_filters(10,10,10,'cat_1','cat_2')

没有传完参数怎么办?

SELECT shop_apply_search_filters(10,10,'cat_1','cat_2')

ERROR:  invalid input syntax for integer: "cat_1"
LINE 1: SELECT shop_apply_search_filters(10,10,'cat_1','cat_2')
                                               ^
SQL state: 22P02
Character: 40

SELECT shop_apply_search_filters(10,10)
ERROR:  function shop_apply_search_filters(integer, integer) is not unique
LINE 1: SELECT shop_apply_search_filters(10,10)
               ^
HINT:  Could not choose a best candidate function. You might need to add explicit type casts.
SQL state: 42725
Character: 8

【问题讨论】:

肯定还有更多事情要做,因为显示的函数和选择绝对有效:dbfiddle.uk/… 看来您有几个具有该名称的重载函数。 【参考方案1】:

为什么不直接使用concat_ws() 一次加入整个字符串?

concat_ws(
    ' and ',
    'price < '      || price_min,
    'price > '      || price_max,
    'ecom_id = '    || ecom_id,
    'category_1 = ' || cat_1,
    'category_2 = ' || cat_2
) 

然后您可以将整个过程简化为:

create or replace function shop_apply_search_filters(
    price_min integer default null, 
    price_max integer default null, 
    ecom_id  integer default null, 
    cat_1 text default null, 
    cat_2 text default null)
returns text as
$$
    select concat_ws(
        ' and ',
        'price < '      || price_min,
        'price > '      || price_max,
        'ecom_id = '    || ecom_id,
        'category_1 = ' || cat_1,
        'category_2 = ' || cat_2
    );
$$
language sql;

【讨论】:

这不是问题中直接问题的一部分,但是:该函数听起来好像它应该创建一个要在 WHERE 子句中使用的条件。在这种情况下,cat_1cat_2 的值可能应该用单引号括起来,例如使用quote_literal()。个别条件也应该与 AND 结合使用。

以上是关于plpgsql 函数 concat 可选参数 返回错误的主要内容,如果未能解决你的问题,请参考以下文章

slice(),splice(),concat()区别

返回查询时如何退出plpgsql函数

plpgsql:使用 2 个 OUT 参数调用函数

返回多列的plpgsql函数被多次调用

为啥我的 plpgsql 函数不返回任何行

从 plpgsql 函数返回多行