2010-01-20 35 views
3

我最近开始使用PostgreSQL,并且正在尝试按照我理解的方式“以正确的方式”执行操作。这意味着将尽可能多的工作放在数据库服务器上,而不是放在客户端上。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; 

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

回答

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,它咬我,它咬了很多人。我没有看到它的需要,所以我建议你避免它。

+0

@EvanCarrorll,你能解释一下你的INSERT INTO ...查询到底在做什么吗? – jeffdill2 2016-01-11 01:54:28

+0

@ jeffdill2截至目前,这是个不好的建议,我会全面更新。 – 2016-01-11 02:52:34

+0

不是问题。我现在已经明白了。我只是通过使用'LEFT JOIN'并在连接表上检查'WHERE ... IS NULL'来实现类似于这种方法的东西。 – jeffdill2 2016-01-11 02:59:01

0

你实际上没有问题。我建议为你的函数提供一个布尔返回值,以便在使用存储过程时更加安心,除非你计划定位PostgreSQL的旧版本添加一个DECLARE部分)。

我强烈推荐书籍PostgreSQL (Developer's Library) by Korry Douglas,它有很多关于在Pl/PgSQL中编写存储过程的资料。我还建议遵循Planet PostgreSQL门户网站聚合来自PostgreSQL社区重要成员的博客文章,因为他们经常讨论使用Postgres解决复杂问题的最佳实践和聪明技巧。祝你好运!

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的文档有使用具有异常处理程序,而不是一个没有处理程序块有关更多的开销,所以这可以节省一些微不足道的开销。

分享和享受。