PostgreSQL插入依赖于另一个表中的数据,最佳实践?

时间:2010-01-20 15:42:38

标签: postgresql function user-defined-functions

我最近开始使用PostgreSQL,我正在尝试以“正确的方式”做事,正如我所理解的那样。这意味着将尽可能多的工作放在数据库服务器而不是客户端上。

所以我创建了一个PL / pgSQL函数,它将数据添加到表中。由于我在该表上设置了主键约束,并且在我尝试添加新数据时可能不存在引用的键我添加了一个异常捕获,它将创建密钥,然后尝试插入新的一行。

这对我来说是令人满意的,但我很好奇我是否正在处理这种“正确的方法”。我一直试图找到一些设计这些用户定义函数的指南,但是我找不到任何有用的东西。

CREATE OR REPLACE FUNCTION add_product_price_promo_xml(v_product_code varchar, v_description varchar, v_product_group varchar,
                                                       v_mixmatch_id integer, v_price_at date, v_cost_price numeric, v_sales_price numeric,
                                                       v_tax_rate integer) RETURNS void AS $$
BEGIN
   INSERT INTO product_prices (product_code  , mixmatch_id  , price_at  , cost_price  , sales_price  , tax_rate) VALUES
                              (v_product_code, v_mixmatch_id, v_price_at, v_cost_price, v_sales_price, v_tax_rate);
EXCEPTION WHEN foreign_key_violation THEN
   INSERT INTO products (code, description, product_group) VALUES (v_product_code, v_description, v_product_group);
   PERFORM add_product_price_promo_xml($1, $2, $3, $4, $5, $6, $7, $8);
END;
$$ LANGUAGE plpgsql;

有问题的数据库将用于制作报告,并将每天导入完整的项目注册,包括价格更新和新项目,但我不知道哪些项目是新的,哪些项目是旧的。

3 个答案:

答案 0 :(得分:4)

没有!!! 错误的方式抱歉,我多年来一直在使用postgresql,这是一个坏主意。正确的方法是(1)创建临时表,(2)更新存在违规(3)插入没有违规的地方。我将使用pg 8.4:

向您展示一个片段
CREATE TEMP TABLE temp_table (
  LIKE table INCLUDING INDEXES INCLUDING CONSTRAINTS
);

然后你想把所有东西都插入temp_table并运行这两个命令。

UPDATE table
SET a = t.a
FROM temp_table AS t
WHERE join-constraints;

INSERT INTO table
SELECT * FROM temp_table AS t
WHERE NOT EXISTS (
    SELECT * FROM table AS v
    WHERE ( join-constraints )
);

如果您愿意,可以在交易中完成,并且您有足够的内存。此方法可以扩展,因为在内部它不会产生大量的checkpoints。它也大规模更快。你当前的方式发布为pseudo-merge routine on Varlena in 2006,它咬了我,它咬了很多人。我认为不需要它,所以我建议你避免它。

答案 1 :(得分:0)

你其实没事。我建议为您的函数提供一个布尔返回值,以便在使用存储过程时更加安心,并按名称引用您的参数,除非您计划定位较旧版本的PostgreSQL(在这种情况下,您需要添加DECLARE部分。)

我强烈推荐这本书PostgreSQL (Developer's Library) by Korry Douglas,它有很多关于在Pl / PgSQL中编写存储过程的资料。我还建议关注Planet PostgreSQL门户网站,该门户网站聚集了PostgreSQL社区知名成员的博客帖子,因为他们经常讨论使用Postgres解决复杂问题的最佳实践和巧妙技巧。祝你好运!

答案 2 :(得分:0)

我认为编写应该在正常情况下不会抛出异常的代码会更好。因为你还是在pl / pgSQL中,为什么不把它写成:

CREATE OR REPLACE FUNCTION add_product_price_promo_xml(v_product_code  varchar,
                                                       v_description   varchar,
                                                       v_product_group varchar, 
                                                       v_mixmatch_id integer,
                                                       v_price_at date,
                                                       v_cost_price numeric, 
                                                       v_sales_price numeric, 
                                                       v_tax_rate integer)
  RETURNS void AS $$ 
DECLARE
  n_count  numeric;
BEGIN
  SELECT COUNT(*)
    FROM products
    INTO n_count
    WHERE code = v_product_code;  -- or whatever the join criteria should be

  IF n_count = 0 THEN
    INSERT INTO products
      (code, description, product_group)
    VALUES
      (v_product_code, v_description, v_product_group);
  END IF;

  INSERT INTO product_prices
    (product_code, mixmatch_id, price_at,
     cost_price, sales_price, tax_rate)
  VALUES 
    (v_product_code, v_mixmatch_id, v_price_at,
     v_cost_price, v_sales_price, v_tax_rate); 
END; 
$$ LANGUAGE plpgsql; 

根据pl / pgSQL文档,与具有异常处理程序的块相关联的开销更多,而不是没有处理程序的块,因此这可能会节省一些微不足道的开销。

分享并享受。