用 INSERT / UPDATE 的单个查询替换循环

2024-03-23

我正在 PostgreSQL 中编写一个函数。它基本上执行 3 个步骤:

  1. 从源表中获取一条记录。
  2. 检查目标表中提取的记录的值,如果在目标表中找到记录,则使用提取的记录更新目标表的所有值,否则将提取的记录插入目标表。

如果我写,而不是做这个循环单一查询对于插入/更新,它会比上述方法更快吗?如何通过编写单个查询而不是循环遍历每个记录并进行更新/插入来获得相同的结果。

我目前的方法如下

CREATE OR REPLACE FUNCTION fun1()
  RETURNS void AS
$BODY$DECLARE
   source_tab_row RECORD;

   v_col1 TEXT;
   v_col2 TEXT;
   v_col3 TEXT;
   v_col4 double precision ;
   cnt integer;

BEGIN
    FOR source_tab_row IN (SELECT * FROM source_tab where col5='abc')
LOOP
    v_col1=source_tab_row.col1;   
    v_col2=source_tab_row.col2;
    v_col3=source_tab_row.col3;
    v_col4=source_tab_row.col4;

    select count(*) INTO cnt from dest_tab where col1=v_col1;

     if (cnt =0) then
     -- If records is not found
       INSERT INTO dest_tab(col1, col2, col3,col4)
       VALUES( v_col1, v_col2, v_col3,v_col4)   ;
    else
     --if records found then update it
       update dest_tab set col1=v_col1, col2=v_col2, col3=v_col3,col4=v_col4
       where col1=v_col1;

     end if;         
END LOOP;
END;
$BODY$ LANGUAGE plpgsql;

更好的 SQL

如果你有 PostgreSQL 9.1 或更高版本,你绝对应该使用数据修改CTE http://www.postgresql.org/docs/current/interactive/queries-with.html#QUERIES-WITH-MODIFYING为了这:

WITH x AS (
   UPDATE dest_tab d
   SET    col2 = s.col2
        , col3 = s.col3
   --   , ...
   FROM   source_tab s
   WHERE  s.col5 = 'abc'
   AND    s.col1 = d.col1

   RETURNING col1
   )
INSERT INTO dest_tab(col1, col2, col3, col4)
SELECT s.col1, s.col2, s.col3, s.col4
FROM   source_tab s
WHERE  s.col5 = 'abc'
LEFT   JOIN x USING (col1)
WHERE  x.col1 IS NULL;

正如@Craig 已经发布的那样,基于集合的 SQL 操作通常比迭代单个行要快得多。

然而,这种形式更快、更简单。它还在很大程度上避免了固有的(微小的!)竞争条件。首先,由于这是单个 SQL 命令,因此时间段甚至更短。此外,如果并发事务应在事务之间输入竞争行,UPDATEINSERT,您会遇到重复密钥违规(前提是您应该有一个 pk / unique 约束)。因为你不查询dest_tab第二次并重复使用原始组INSERT。更快,更好。

如果您看到重复的键违规:没有发生任何不好的事情,只需重试查询即可。

It does not涵盖了并发事务的相反情况DELETE与此同时。在我看来,这确实是不太重要/不常见的情况。

正确的plpgsql

If为此,您使用 plpgsql,简化:

CREATE OR REPLACE FUNCTION fun1()
  RETURNS void AS
$BODY$
DECLARE
   _source source_tab;  -- name of table = type
BEGIN
   FOR _source IN
      SELECT * FROM source_tab where col5 = 'abc'
   LOOP
        UPDATE dest_tab
        SET    col2 = _source.col2  -- don't update col1, it doesn't change
               ,col3 = _source.col3
               ,col4 = _source.col4
        WHERE  col1 = _source.col1;

      IF NOT FOUND THEN  -- no row found
         INSERT INTO dest_tab(col1, col2, col3,col4)
         VALUES (_source.col1, _source.col2, _source.col3, _source.col4);
      END IF;

   END LOOP;
END
$BODY$ LANGUAGE plpgsql;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

用 INSERT / UPDATE 的单个查询替换循环 的相关文章

  • 如何在一列中存储数组或多个值

    运行 Postgres 7 4 是的 我们正在升级 我需要将 1 到 100 个选定项目存储到数据库的一个字段中 98 的情况下 只会输入 1 个项目 而 2 的情况下 如果是这样的话 会输入多个项目 这些项目只不过是文本描述 截至目前 长
  • 如何终止正在运行的 SELECT 语句

    如何通过终止会话来停止正在运行的 SELECT 语句 该命令不断根据 SELECT 语句向我提供输出 我想在其间停止它 As you keep getting pages of results I m assuming you starte
  • sqlalchemy 的 row_to_json 语法

    我想弄清楚如何将 Postgres 9 2 row to json 与 SqlAlchemy 一起使用 但是我无法想出任何有效的语法 details foo row q select Foo where Foo bar id Bar id
  • 一组记录中某些值相同的唯一约束

    DBMS MS Sql Server 2005 标准版 我想创建一个表约束 以便只有一个记录在表的子集中具有特定值 其中行共享特定列中的值 这可能吗 Example 我的 myTable 中有一些记录 其中有一个非唯一的外键 fk1 以及一
  • pg_stat_activity 中具有“空闲”状态的持久“COMMIT”查询

    如果我查询 select from pg stat activity where application name example application 我得到了很多行 哪个州是idle查询是COMMIT 它们是持久的并且不会消失 一段时
  • 在 SQL Server 中选择条件的值[重复]

    这个问题在这里已经有答案了 在查询选择中 我想显示字段是否满足条件的结果 想象一下我有一张名为stock 该表有一列告诉我库存中每种商品的数量 我想做的是这样的 SELECT stock name IF stock quantity lt
  • 如何将 T-SQL 中的结果连接到列中?

    我正在处理一个查询 它应该给我这样的结果 Name Surname Language Date James Hetfield en gb fr 2011 01 01 Lars Ulrich gb fr ca 2011 01 01 但我的选择
  • 导致聚集索引扫描的日期参数

    我有以下查询 DECLARE StartDate DATE 2017 09 22 DECLARE EndDate DATE 2017 09 23 SELECT a col1 a col2 b col1 b col2 b col3 a col
  • 从 ISO 周中提取日期 (201905) BigQuery

    我需要从 ISO 周数中提取星期日的日期 即 201905 它需要位于 standardSQL 中 因为它将使用不支持旧版本的脚本进行调度 我尝试从 Google Sheets 调整工作公式 但无法弄清楚 Google Sheets 的原始
  • Oracle Many OR 与 IN () 的 SQL 性能调优 [重复]

    这个问题在这里已经有答案了 我手头没有 解释计划 您能帮忙判断以下哪一个更有效吗 选项1 select from VIEW ABC where STRING COL AA OR STRING COL BB OR STRING COL BB
  • MySQL:用户对数据库的访问被拒绝

    我正在尝试在 Heroku 上的远程 SQL 服务器上创建一个数据库 clearDB 我与此联系 mysql host lt
  • 动态SQL生成列名?

    我有一个查询 我正在尝试将行值转换为列名称 目前我正在使用SUM Case As ColumnName 声明 像这样 SELECT SKU1 SUM Case When Sku2 157 Then Quantity Else 0 End A
  • 设置约束可延迟在 PostgreSQL 事务上不起作用

    情况是这样的 我有两个表 其中一个引用另一个 例如 table2 引用 table1 创建这些表时 我确实将外键约束设置为 DEFERRABLE 将 ON UPDATE 和 ON DELETE 子句设置为 NO ACTION 这是默认值 但
  • 出于安全目的,您是否有理由不执行自己的算法来打乱 ID?

    我计划实现我自己的非常简单的 哈希 公式 为具有多个用户的应用程序添加一层安全性 我目前的计划如下 用户创建一个帐户 此时后端会生成一个 ID ID 通过公式运行 假设 ID 57 8926 36 7 或同样随机的东西 然后 我将新的用户
  • 数据库“key/ID”设计思想、代理键、主键等

    因此 我最近看到多次提到代理键 但我不太确定它是什么以及它与主键有何不同 我总是假设 ID 是表中的主键 如下所示 Users ID Guid FirstName Text LastName Text SSN Int 然而 维基百科将代理键
  • 如何比较表中最后一个和倒数第二个条目的值?

    我在 Oracle 中有一个名为quotes 的表 其中包含两列 date 和value 我想比较表中最后一个条目和倒数第二个条目的值 在此示例中 我想获取日期13 1 和 11 1在一行中以及每个日期的值之间的差异 10 5 5 报价表
  • org.postgresql.util.PSQLException:协议错误。会话设置失败

    我知道这些类型的问题已经存在 但提供的解决方案对我不起作用 在我的应用程序中 没有版本不匹配的黑白驱动程序和 PostgreSQL 服务器 我还没有找到任何其他解决方案 我正在使用 PostgreSQL 服务器 9 4 和 postgres
  • 如何查询多对多表(一个表的值成为列标题)

    给定此表结构 我想展平多对多关系 并将一个表的名称字段中的值设置为列标题 并将同一表中的数量设置为列值 目前可行的想法是将值放入字典 哈希表 中并用代码表示这些数据 但我想知道是否有 SQL 方法可以做到这一点 我还使用 Linq to S
  • 安全转义表名/列名

    我在 php 中使用 PDO 因此无法使用准备好的语句转义表名或列名 以下是我自己实现它的万无一失的方法 tn str replace REQUEST tn column str replace REQUEST column sql SEL
  • 在单个查询中设置和选择?

    我想知道是否可以在单个查询中设置和选择 像这样的事情 SET LOCAL search path TO 1 SET LOCAL ROLE user SELECT from posts 你可以这样做 with some set as sele

随机推荐