多次调用 UPSERT 函数到不同的输入

Han*_*ans 2 postgresql functions upsert

我有一个功能:

merge_vehicles(vid, cid, vname, reg_no, name, name_1st)
Run Code Online (Sandbox Code Playgroud)

我可以在输入上多次调用它吗

(2335, 55, '246BDH', '246BDH', '811', 1),
(2336, 55, '038THX', '038THX', '831', 1),
....
Run Code Online (Sandbox Code Playgroud)

该函数是一个UPSERT实现返回void. 这是一个仓库数据库(事实表)。我们有一个实时数据库,每小时可以获取 1000 多个输入。我们想使用此命令将我们的数据与新数据合并。

它是一个表函数。(我已经为我们拥有的每个表定义了类似的函数 - 即 5。)结果是,它将更新现有行(如果存在),否则插入新行。

Postgres 版本是 9.3。

函数是此处接受的答案的一个版本:

Erw*_*ter 5

UPSERT 一次执行 1 行功能

“表函数”是一个返回一组行的函数(当用 调用时就像一个表SELECT * FROM myfunc())。你所拥有的不是表函数。由于没有返回任何内容,您可以使用一个简单的调用:

SELECT merge_vehicles(vid, cid, vname, reg_no, name, name_1st)
FROM  (
   VALUES
     (2335, 55, '246BDH', '246BDH', '811', 1::numeric) -- example for explicit cast
    ,(2336, 55, '038THX', '038THX', '831', 1)
    , ...
   ) t(vid, cid, vname, reg_no, name, name_1st)        -- arbitrary column names
Run Code Online (Sandbox Code Playgroud)

虽然这样做有效,但一次插入 1 行对于大集合来说效率很低

批量UPSERT

假设(vid, cid)是我们表的主键test(信息丢失),我建议在取出EXCLUSIVE LOCK表后为 UPSERT 进行数据修改 CTE 。

EXCLUSIVE LOCK仍然允许并发事务从表中读取,但是没有写入。仅当您确实可以将并发事务写入同一个表时才需要。

BEGIN;

LOCK TABLE test IN EXCLUSIVE MODE;

-- Or use a temp table for new rows. See below.
WITH my_rows(vid, cid, vname, reg_no, name, name_1st) AS (
   VALUES
      (2335, 55, '246BDH', '246BDH', '811', 1::numeric) -- example for explicit cast
     ,(2336, 55, '038THX', '038THX', '831', 1)
     , ...
   )
, upd AS (
    UPDATE test t
    SET   (  vname,   reg_no,   name,   name_1st)
        = (m.vname, m.reg_no, m.name, m.name_1st)
    FROM   my_rows m
    WHERE  t.vid = m.vid        -- match on PK columns
    AND    t.cid = m.cid
    RETURNING t.vid, t.cid      -- return only PK columns
    )
INSERT INTO test
      (  vid,   cid,   vname,   reg_no,   name,   name_1st)
SELECT m.vid, m.cid, m.vname, m.reg_no, m.name, m.name_1st
FROM   my_rows m
LEFT   JOIN upd USING (vid, cid)
WHERE  u.vid IS NULL;           -- only remaining rows

COMMIT;                         -- releases all locks
Run Code Online (Sandbox Code Playgroud)

如果列表很长,请考虑填充临时表COPY以替换 CTEmy_rows及其VALUES表达式。

有关的:

在一个 SELECT 中多次调用设置返回函数

(在更新问题之前)

假设我们正在处理一个集合返回函数(又名“表函数”)。

您可以将VALUES表达式用于参数派生表(或任何其他派生表或实际表)的文字输入,并方便地使用LATERAL JOIN(Postgres 9.3+)在一个查询中获得统一结果。您可能想以某种方式订购...

SELECT f.*
FROM  (
   VALUES
     (2335, 55, '246BDH', '246BDH', '811', 1::numeric) -- example for explicit cast
    ,(2336, 55, '038THX', '038THX', '831', 1)
    , ...
   ) t(vid, cid, vname, reg_no, name, name_1st)        -- arbitrary column names
     , merge_vehicles(vid, cid, vname, reg_no, name, name_1st) f;
Run Code Online (Sandbox Code Playgroud)

LATERAL JOIN是隐含在函数调用FROM列表。更多细节在这里:

本例中的数字文字默认为 type integer,字符串文字变为text. 如果您需要特定类型,请添加显式强制转换。


归档时间:

查看次数:

1607 次

最近记录:

5 年,7 月 前