我一直在尝试创建一个View,其中一个pending_amount列由于存储过程执行而获取其值。
存储过程是 pending_stock(int,int)并返回一个整数。视图已成功创建,但是当我尝试在此视图上执行任何查询时,只需返回一个值。
CREATE OR REPLACE VIEW view_production_parts AS
SELECT p.part_id, p.min_amount, gp.part_num, gp.description
, p.quantity_available
, p.quantity_total - p.quantity_available AS quantity_alloc
, p.quantity_total
, (SELECT pending_stock(p.part_id, 0) AS pending_stock) AS pending_amount
, p.production_run
, CASE
WHEN ppur.purchased_part_id IS NOT NULL THEN true
ELSE false
END AS is_purchased_part, ppur.purchased_part_id, p.store_move_type_id
, gp.part_status_id, p.default_location
, COALESCE(pwoh.part_work_order_hold_id, 0) AS part_work_order_hold_id
FROM general_part gp
JOIN part p ON gp.part_id = p.part_id
LEFT JOIN purchased_part ppur ON ppur.part_id = p.part_id
LEFT JOIN part_work_order_hold pwoh ON pwoh.part_id = p.part_id
ORDER BY gp.part_num;
可以在视图中使用存储过程吗?如果使用,我的声明是否正确?
找到result from of this query at explain.depesz.com:
EXPLAIN ANALYZE SELECT count(*) FROM view_production_parts
我正在使用Postgres 8.4
pending_stock(int,int)
的函数定义:
CREATE OR REPLACE FUNCTION pending_stock(var_part_id integer
, var_pattern_id integer)
RETURNS integer AS
$BODY$
declare
r record;
var_qty_expected integer;
var_qty_moved_to_stock integer;
var_total_stock_moved_out integer;
var_actual_qty integer;
begin
var_total_stock_moved_out := 0;
var_qty_expected := 0;
for r in
select work_order_id,quantity_expected
from view_work_orders
where part_id = var_part_id and open = 'TRUE'
and quantity_allocated is null and quantity_expected >= quantity_actual
loop
var_qty_expected = var_qty_expected + r.quantity_expected;
select sum(quantity) from view_work_order_move_parts_details
where source_work_order_id = r.work_order_id
and part_id = var_part_id into var_qty_moved_to_stock;
if var_qty_moved_to_stock is null then
var_qty_moved_to_stock = 0;
end if;
var_total_stock_moved_out = var_total_stock_moved_out
+ var_qty_moved_to_stock;
end loop;
var_actual_qty := var_qty_expected - var_total_stock_moved_out;
if var_actual_qty > 0 then
return var_actual_qty;
else
return 0;
end if;
end;
$BODY$
LANGUAGE 'plpgsql' VOLATILE STRICT
COST 100;
ALTER FUNCTION pending_stock(integer, integer) OWNER TO postgres;
答案 0 :(得分:1)
您不需要函数调用的子查询。您可以简化其他一些细节:
CREATE OR REPLACE VIEW view_production_parts AS
SELECT p.part_id, p.min_amount
, gp.part_num, gp.description, p.quantity_available
, p.quantity_total - p.quantity_available AS quantity_alloc
, p.quantity_total
, pending_stock(gp.part_id, 0) AS pending_amount
, p.production_run
,(ppur.purchased_part_id IS NOT NULL) AS is_purchased_part
, ppur.purchased_part_id, p.store_move_type_id, gp.part_status_id
, p.default_location
, COALESCE(pwoh.part_work_order_hold_id, 0) AS part_work_order_hold_id
FROM general_part gp
JOIN part p USING (part_id)
LEFT JOIN purchased_part ppur USING (part_id)
LEFT JOIN part_work_order_hold pwoh USING (part_id)
ORDER BY gp.part_num;
除此之外,VIEW定义看起来很好。
可以大大简化:
CREATE OR REPLACE FUNCTION pending_stock(var_part_id integer
, var_pattern_id integer)
RETURNS integer AS
$func$
DECLARE
r record;
var_qty_expected integer := 0;
var_total_stock_moved_out integer := 0;
BEGIN
FOR r IN
SELECT work_order_id, quantity_expected
FROM view_work_orders
WHERE part_id = var_part_id
AND open = 'TRUE' -- A string instead of a boolean?
AND quantity_allocated IS NULL
AND quantity_expected >= quantity_actual
LOOP
var_qty_expected := var_qty_expected + r.quantity_expected;
SELECT var_total_stock_moved_out + COALESCE(sum(quantity), 0)
FROM view_work_order_move_parts_details
WHERE source_work_order_id = r.work_order_id
AND part_id = var_part_id
INTO var_total_stock_moved_out;
END LOOP;
RETURN GREATEST(var_qty_expected - var_total_stock_moved_out, 0);
END
$func$ LANGUAGE plpgsql
通常,plpgsql中的赋值相对较贵。每个赋值都在内部执行(非常简单快速)SELECT
语句。尽量少用它们。
您可以在声明时初始化变量。无需另外发表声明。
The assignment operator in plpgsql is :=
。 =
有效,但没有记录。
使用COALESCE()
来捕获NULL
值。
从不使用函数参数var_pattern_id
。这可能不是完整的功能定义。
使用GREATEST
现在,这个清理过的功能会快一些,但不会太多。你反复循环的整个设计是非常低效。它导致相关的子查询再次循环通过相关的子查询。表演噩梦。
将问题重新设置为基于集合的操作,以使其更快。好吧, 很多 更快。
SELECT e.part_id
,GREATEST(COALESCE(sum(e.quantity_expected), 0)
- COALESCE(sum(m.total_stock_moved_out), 0), 0)
FROM view_work_orders e
LEFT JOIN (
SELECT source_work_order_id AS work_order_id
,COALESCE(sum(quantity), 0) AS total_stock_moved_out
FROM view_work_order_move_parts_details
WHERE part_id = var_part_id
GROUP BY 1
) m USING (work_order_id)
WHERE e.part_id = var_part_id
AND e.open = 'TRUE'
AND e.quantity_allocated IS NULL
AND e.quantity_expected >= e.quantity_actual
GROUP BY 1;
将其整合到原始查询/视图中:
CREATE OR REPLACE VIEW view_production_parts AS
SELECT p.part_id, p.min_amount
,gp.part_num, gp.description, p.quantity_available
,p.quantity_total - p.quantity_available AS quantity_alloc
,p.quantity_total
,x.pending_amount
,p.production_run
,(ppur.purchased_part_id IS NOT NULL) AS is_purchased_part
,ppur.purchased_part_id, p.store_move_type_id, gp.part_status_id
,p.default_location
,COALESCE(pwoh.part_work_order_hold_id, 0) AS part_work_order_hold_id
FROM general_part gp
JOIN part p USING (part_id)
LEFT JOIN purchased_part ppur USING (part_id)
LEFT JOIN part_work_order_hold pwoh USING (part_id)
LEFT JOIN (
SELECT e.part_id
,GREATEST(COALESCE(sum(e.quantity_expected), 0)
- COALESCE(sum(m.total_stock_moved_out), 0)
, 0) AS pending_amount
FROM view_work_orders e
LEFT JOIN (
SELECT source_work_order_id AS work_order_id
,sum(quantity) AS total_stock_moved_out
FROM view_work_order_move_parts_details
WHERE part_id = var_part_id
GROUP BY 1
) m USING (work_order_id)
WHERE e.part_id = var_part_id
AND e.open = 'TRUE'
AND e.quantity_allocated IS NULL
AND e.quantity_expected >= e.quantity_actual
GROUP BY 1
) x USING (part_id)
ORDER BY gp.part_num;
显然未经测试。