Postgres从存储函数返回数组

时间:2017-07-02 09:33:04

标签: postgresql-9.4

我试图从存储的函数返回数组,并在where子句中使用它的输出,用于查询。但它不是出于不明原因而工作。我真的没有线索。请帮忙。

使用以下功能。

CREATE OR REPLACE FUNCTION terep_cstm.testdays(
    v_in_date date,
    v_n integer)
  RETURNS text[] AS
$BODY$ 
declare
listndays text = '';
arrndays text[];          
BEGIN   
    for i in 0..v_n 
    loop
    listndays = listndays||''||(v_in_date - i*interval '1 day')::date::text||',';
    end loop;
    listndays =  trim(trailing ',' from listndays); 
    arrndays = string_to_array(listndays,',');                
return arrndays; 
END
$BODY$
  LANGUAGE plpgsql VOLATILE;

使用存储的函数执行此查询。

select  retl_code,price_2, attr_1,start_date,price,printedprice 
from    tessttable abc 
where   abc.attr_1 = '011' and abc.price_2 = '034' and abc.retl_code = '00068247' 
        and abc.start_date = ANY (select testdays('2017-05-31'::date,7))  --'2017-05-31'
        --and abc.start_date = ANY (ARRAY['2017-05-31','2017-05-30','2017-05-29','2017-05-28','2017-05-27','2017-05-26','2017-05-25','2017-05-24'])  
        --and abc.start_date in ('2017-05-31','2017-05-30','2017-05-29','2017-05-28','2017-05-27','2017-05-26','2017-05-25','2017-05-24');

这对任何运算符都不起作用,错误消息

错误:运算符不存在:text = text [];

请让我知道我在哪里弄错了。 abc。 start_date数据类型是文本,它是平台配置的。不幸的是,我们没有自由转换此列数据类型,只能携带这个。

似乎与

一起使用
and abc.start_date = ANY (testdays('2017-05-31'::date,7));

但是查询被绞死了很长时间。我也可以看到解释计划中的不同。

Query:
select  retl_code,price_2, attr_1,start_date,price,printedprice 
from    tessttable abc 
where   abc.attr_1 = '011' and abc.price_2 = '034' and abc.retl_code = '00068247'      
        and abc.start_date in ('2017-05-31','2017-05-30','2017-05-29','2017-05-28','2017-05-27','2017-05-26','2017-05-25','2017-05-24');
Explain Plan:       
"Index Scan using tessttable_comp_date on tessttable abc  (cost=0.70..41.70 rows=1 width=43)"
"  Index Cond: ((start_date = ANY ('{2017-05-31,2017-05-30,2017-05-29,2017-05-28,2017-05-27,2017-05-26,2017-05-25,2017-05-24}'::text[])) AND (prd_price_attr_1 = '011'::text) AND (price_2 = '034'::text) AND (retl_code = '00068247': (...)"

Query:
select  retl_code,price_2, attr_1,start_date,price,printedprice 
from    tessttable abc 
where   abc.attr_1 = '011' and abc.price_2 = '034' and abc.retl_code = '00068247' 
        and abc.start_date = ANY (testdays('2017-05-31'::date,7)) ;  
Explain Plan:
"Index Scan using tessttable_comp_date on tessttable abc  (cost=0.70..10285844.48 rows=4 width=43)"
"  Index Cond: ((prd_price_attr_1 = '011'::text) AND (price_2 = '034'::text) AND (retl_code = '00068247'::text))"
"  Filter: (start_date = ANY (just_n_days('2017-05-31'::date, 7)))"

1 个答案:

答案 0 :(得分:2)

摆脱选择,只需将函数用作表达式:

and abc.start_date = ANY ( testdays('2017-05-31'::date,7) )

如果将abc.start_date定义为date,则不应将日期值与字符串数组进行比较。使函数返回date[]

该函数也可以简化为简单的SQL函数,不需要PL / pgSQL:

CREATE OR REPLACE FUNCTION testdays(v_in_date date, v_n integer)
  RETURNS date[] AS
$BODY$ 
   select array_agg(x::date) 
   from generate_series(current_date, current_date  + 6, interval '1' day) x;
$BODY$
LANGUAGE sql;

要坚持使用错误的日期文本值,只需更改汇总的内容

CREATE OR REPLACE FUNCTION testdays(v_in_date date, v_n integer)
  RETURNS text[] AS
$BODY$ 
   select array_agg(to_char(x, 'yyyy-mm-dd')) 
   from generate_series(current_date, current_date  + 6, interval '1' day) x;
$BODY$
LANGUAGE sql;

请注意,我将返回类型更改为date[],以便您将日期与日期进行比较。

但是,我不明白为什么你首先需要一个功能:

and abc.start_date between date '2017-05-31' and date '2017-05-31' + 7

将实现完全相同的事情,并且在大多数情况下会更快。