【问题标题】:PostgreSQL insert that depends on data in another table, best practice?PostgreSQL插入依赖于另一个表中的数据,最佳实践?
【发布时间】:2011-01-07 08:08:54
【问题描述】:

我最近开始使用 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;

有问题的数据库将用于制作报告,并将每天导入完整的商品登记册,其中包含价格更新和新商品,但我不知道哪些商品是新的,哪些是旧的。

【问题讨论】:

    标签: postgresql function user-defined-functions


    【解决方案1】:

    我认为最好编写在正常情况下不抛出异常的代码。既然你在 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 文档,与没有异常处理程序的块相比,具有异常处理程序的块会产生更多开销,因此这可能会节省一些微不足道的开销。

    分享和享受。

    【讨论】:

      【解决方案2】:

      不!!! 错误的方式 抱歉,我已经使用 postgresql 多年了,这是个坏主意。正确的方法是(1)创建一个临时表,(2)在有违规的地方更新(3)在没有违规的地方插入。我将使用 pg 8.4 向您展示一个 sn-p:

      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,它咬了我,它咬了很多人。我认为没有必要,所以我建议您避免使用它。

      【讨论】:

      • @EvanCarrorll,您能解释一下您的INSERT INTO... 查询到底在做什么吗?
      • @jeffdill2 这是一个糟糕的建议,我会完全更新。
      • 没问题。我现在真的想通了。我刚刚通过使用LEFT JOIN 并在连接表上检查WHERE ... IS NULL 来实现与该方法类似的东西。
      【解决方案3】:

      你实际上做得很好。我建议您也为您的函数提供一个布尔返回值,以便在使用存储过程时更加安心,并通过名称引用您的参数,除非您计划针对旧版本的 PostgreSQL(在这种情况下,您需要添加一个 DECLARE 部分)。

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

      【讨论】:

        猜你喜欢
        • 2010-12-11
        • 1970-01-01
        • 2010-10-04
        • 2019-08-24
        • 2011-12-30
        • 1970-01-01
        • 2019-05-23
        • 2011-06-25
        相关资源
        最近更新 更多