【问题标题】:Parameterised Order by not working in postgresql通过不在 postgresql 中工作的参数化顺序
【发布时间】:2017-07-15 10:12:13
【问题描述】:

我是postgresql 的新手。我正在尝试编写一个用于搜索的postgresql 函数,该函数将仅返回匹配的 ID,并将订单 ID 作为参数中提供的列名返回。

我尝试以不同的方式解决问题。

如果排序列在结果集中没有,我已经阅读了在条件情况下不排序数据的顺序。但是我编写的下面的函数,如果在 DB 中提供的列类型是 文本/字符变化/日期,则返回 ASC 中的 ID,我测试过。对于 integer/float 类型的列根本不排序 ID。现在,我需要根据需要对整数/浮点类型列以及 ASC/DESC 进行排序。

CREATE OR REPLACE FUNCTION public.search_products(_name text DEFAULT NULL::text, _category_id integer DEFAULT NULL::integer, _min_mrp double precision DEFAULT NULL::double precision, _max_mrp double precision DEFAULT NULL::double precision, _sort_field text DEFAULT NULL::text)
 RETURNS SETOF bigint
 LANGUAGE sql
AS $function$

    select product.id 
        from product
        where
            case
                when _category_id is null then (_name is null or lower(product.name) like '%'|| lower(_name) ||'%' and (_min_mrp is null or _max_mrp is null Or (product.market_retail_price BETWEEN _min_mrp and _max_mrp)))
                when _category_id is not null then (_name is null or lower(product.name) like '%'|| lower(_name) ||'%' and (_min_mrp is null or _max_mrp is null Or (product.market_retail_price BETWEEN _min_mrp and _max_mrp))) /*will be updated after category id deciding */
            end

            ORDER BY
                CASE 
                    WHEN(_sort_field similar to 'market_retail_price asc') THEN product.market_retail_price || ' ASC' /* it is float type column, and not working for asc/desc anything */
                    WHEN(_sort_field similar to 'approved_by asc') THEN product.approved_by || ' ASC' /* it is integer type column, and not working for asc/desc anything */
                    WHEN(_sort_field similar to 'approved_on asc') THEN product.approved_on || ' ASC' /* date type column, it works for asc order only. Even if text is 'approved_on desc' in other case, it match the case, but returns data in asc order only. THAT'S TOTALLY WIERED. Never sort desc. */
                    WHEN(_sort_field similar to 'supplier_id asc') THEN product.supplier_id || ' ASC'
                    WHEN(_sort_field similar to 'product_status asc') THEN product.product_status || ' ASC' /* text type, and working for asc only */
                    WHEN(_sort_field similar to 'name desc') THEN (product.name || ' DESC') /* not working for desc order, but returns data in asc sort */
                    ELSE product.id || ' ASC'
                END
$function$

我也尝试这种方式订购太简单了:
ORDERY BY _sort_field

ORDER BY quote_ident(_sort_field);
如果类型为 text/date/integer/float,它不会对任何列进行 asc/desc 排序!

我使用的是 postgresql-9.5.1-1-windows-x64 版本

【问题讨论】:

  • 你必须使用dynamic SQL 来做类似的事情。小心 SQL 注入!

标签: database postgresql sql-parametrized-query sql-order-by


【解决方案1】:

最后,我使用动态查询解决了我的问题(虽然动态查询很痛苦)。如果没有动态查询,我无法将 orderby(ASCDESC)问题修复为提供的参数。这是修改后的功能。谢谢@ClodoaldoNeto。和另一个实际上指示我使用动态查询的人。

这是功能,希望这对其他人也有帮助:

CREATE OR REPLACE FUNCTION public.search_products(_name text DEFAULT NULL::text, _category_id integer DEFAULT NULL::integer, _min_mrp double precision DEFAULT NULL::double precision, _max_mrp double precision DEFAULT NULL::double precision, _sort_column_name text DEFAULT NULL::text, _sorting_type text DEFAULT 'asc'::text)
 RETURNS SETOF bigint
 LANGUAGE plpgsql
AS $function$
BEGIN

    if($1 is not null) then
        $1 := '%'||$1||'%';
    end if;

    RETURN QUERY EXECUTE
    'SELECT product.id
    FROM product
    WHERE (($1 is null OR product.name ~~* $1) AND ($3 is null OR $4 is null OR (product.market_retail_price BETWEEN $3 and $4)) AND ( $2 IS NULL OR (product.id IN (SELECT product_category_map.product_id FROM product_category_map where product_category_map.category_id = $2))))
    ORDER BY ' 
        || quote_ident($5) 
        || ' '
        || $6
    USING _name, _category_id, _min_mrp, _max_mrp, _sort_column_name, _sorting_type; 

END;
$function$

【讨论】:

    【解决方案2】:

    ascdesc 是关键字,不能作为排序表达式的一部分。这个数组诡计会做到这一点:

    order by
        (array [
            to_char(p.market_retail_price, '00000000009'),
            p.approved_by,
            to_char(p.approved_on, 'YYYY-MM-DD'),
            to_char(p.supplier_id, '00000000009'),
            p.product_status
        ])
        [array_position (
            array [
                'market_retail_price asc',
                'approved_by asc',
                'approved_on asc',
                'supplier_id asc',
                'product_status asc'
            ], _sort_field
        )] asc,
        (array [p.name])[array_position (array ['name desc'], _sort_field)] desc
    

    【讨论】:

    • 数组不能包含不同类型的值。
    • @Abelisto 我想我已经解决了。
    • IMO to_jsonb 更通用,例如:with x(i,t,d) as (values(11,'a'::text, '1111-11-11'::date),(2,'b','2222-12-22')) select * from x order by to_jsonb(i);
    猜你喜欢
    • 1970-01-01
    • 2011-11-23
    • 1970-01-01
    • 1970-01-01
    • 2015-08-22
    • 2018-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多