我有一个vehicle_data
表:
CREATE TABLE public.vehicle_data (
model_name text NOT NULL,
record_date text NOT NULL,
actual_inv_days real,
forecasted_inv_days real[],
CONSTRAINT vehicle_data_pkey PRIMARY KEY (model_name, record_date)
)
因此我的桌子看起来像这样:
model_name record_date actual_inv_days forecasted_inv_days
car1 1-2015 33 {22,33,11,22,33,44}
car1 2-2015 22 {25,35,10,22,30}
car1 3-2015 30 {32,30,20,11}
我想为用户选择的月份 n 创建一个合并数组,该数组显示月份 1..n 中的actual_inv_days
,然后一个数组中每月{em> n 的forecasted_inv_days
。 merged_array('car1',2015,3)
的结果将是:
{33,22,30,32,30,20,11}
下面的函数可以作为一个DO
块正常工作,但是当我将其修改为一个函数时,它似乎比所需的循环了68次。 这是我编写的每个函数的事,我不知道该怎么办。
-- DROP FUNCTION public.merged_array(text, integer, integer);
CREATE OR REPLACE FUNCTION public.merged_array(model text, yr integer, pivot integer)
RETURNS real[] AS
$BODY$
DECLARE actual_arr real[];
element real;
final_arr real[];
BEGIN
FOR i IN 1..pivot
LOOP
element:= (
SELECT actual_inv_days
FROM vehicle_data
WHERE model_name = model
AND split_part(record_date,'-',2)::int = yr
AND split_part(record_date,'-',1)::int = i);
-- append new element to existing array
actual_arr:= actual_arr||element;
END LOOP;
final_arr:= actual_arr||(
SELECT forecasted_inv_days
FROM vehicle_data
WHERE model_name= model
AND split_part(record_date,'-',2)::int = yr
AND split_part(record_date,'-',1)::int = pivot);
RETURN final_arr;
END$BODY$
LANGUAGE plpgsql;
我想做的是:
创建actual_array
,在其中添加actual_inv_days
作为元素,针对特定年份(model
)的特定yr
,将所选月份作为{ {1}}。
一个月一个月地走,直到达到“枢轴月”,其中满足模型和年份。
创建一个pivot
,将final_array
和actual_array
数组合并。
答案 0 :(得分:1)
我认为您的代码中没有理由“循环68次超过必要次数” 。
尽管如此,就像a_horse所说的那样,所有这些都应该是一个查询。您的数据模型可以从重新设计中受益-尤其是record_date
列。字符串1-2015
的字符串是存储该信息的最不理想的方法之一。甚至不允许简单的范围查询。 (2015-01
那样会更有用,但仍然不是最佳选择。)
两个integer
列会更好。
我将使用单个date
,将其截断为月份,因为它最适合要存储的信息。占用4个字节。
然后您的表可能如下所示(其他所有内容不变):
CREATE TABLE vehicle_data (
model_name text NOT NULL
, record_date date NOT NULL
, actual_inv_days real
, forecasted_inv_days real[]
, CONSTRAINT record_date_truncated_to_month CHECK (date_trunc('month', record_date) = record_date)
, CONSTRAINT vehicle_data_pkey PRIMARY KEY (model_name, record_date)
);
然后,您可以将查询包装到此简单的SQL函数中,该函数可以替代旧的函数:
CREATE OR REPLACE FUNCTION public.merged_array(model text, yr integer, pivot integer)
RETURNS real[] AS
$func$
SELECT forecasted_inv_days
|| ARRAY (
SELECT actual_inv_days
FROM vehicle_data
WHERE model_name = $1
AND record_date BETWEEN to_date(yr::text, 'YYYY')
AND to_date(yr||'-'||pivot, 'YYYY-MM')
ORDER BY record_date
)
FROM vehicle_data
WHERE model_name = model
AND record_date = to_date(yr||'-'||pivot, 'YYYY-MM')
$func$ LANGUAGE sql;
当然,您现在也可以传递一个实际日期(截断为月份)...
关于to_date()
和date_trunc()
的手册。
关于上面的相关子查询中使用的ARRAY构造函数: