【问题标题】:Execute Postgresql function that accepts an array of parameters using pg-promise使用 pg-promise 执行接受参数数组的 Postgresql 函数
【发布时间】:2020-06-28 04:15:16
【问题描述】:

我们有这个 postgresql 类型:

create type order_input as (
    item text,
    quantity integer);

还有这个 postgresql 函数:

create or replace function insert_into_orders(order_input[])
returns void language plpgsql as $$
declare 
    inserted_id integer;
begin
    insert into public.orders(orderdate) 
    values (now()) 
    returning orderid into inserted_id;

    insert into public.orderdetails(orderid, item, quantity)
    select inserted_id, item, quantity
    from unnest($1);
end $$;

要在 pgadmin-4 中执行,我们运行:

select insert_into_orders(
    array[
        ('Red Widget', 10), 
        ('Blue Widget', 5)
    ]::order_input[]
);

我试图弄清楚如何使用 pg-promise javascript 库执行 insert_into_orders 函数。我尝试过以下操作:

const pgp = require("pg-promise")();
const db = pgp(connectionObj);

await db.func("insert_into_orders", [{item:"Red Widget", quantity:10}, {item:"Blue Widget", quantity:5}]

但收到以下消息:

{
  "error": {
    "message": "malformed array literal: \"{\"item\":\"Red Widget\", \"quantity\":10}\""
  }
}

如果有人知道我必须如何为 pg-promise 构建我的输入,我将不胜感激,原帖来自这里:Postgres Function to insert multiple records in two tables

【问题讨论】:

    标签: javascript postgresql pgadmin pgadmin-4 pg-promise


    【解决方案1】:

    方法func 需要一个值数组作为第二个参数。在您的情况下,它必须是一个参数 - 对象数组。但是您改为给它 2 个参数,每个参数都是一个对象,因此会出现错误。

    正确的做法是:

    const orderInput = [{item:"Red Widget", quantity:10}, {item:"Blue Widget", quantity:5}];
    
    await db.func('insert_into_orders', [orderInput]);
    

    无论如何,您应该使用事件querypg-monitor 来查看生成了什么SQL。

    另外,您的insert_into_orders 至少应该是stored procedure,然后通过proc 执行。但是,它的实现看起来应该只是代码中的一个事务。

    执行此操作后,错误返回为"error": {"message": "function insert_into_orders(text[]) does not exist"}

    那是因为类型不匹配,需要类型转换...

    您可以通过常规查询方法调用该函数,也可以使用Custom Type Formatting修改数据格式:

    const data = {
        toPostgres: () => `${pgp.as.array(orderInput)}::json[]::order_input[]`,
        rawType: true
    };
    

    然后将其传入:

    await db.func('insert_into_orders', [data]);
    

    【讨论】:

    • 感谢您的建议,它们非常有用!我添加了事件查询,生成的执行查询是select * from insert_into_orders(array[('Red Widget', 10), ('Blue Widget', 5)])。执行此操作后,错误返回为{ "error": { "message": "function insert_into_orders(text[]) does not exist" } },因为此postgresql 函数期待insert_into_orders(order_input[])。你知道是否有办法将输入数据映射到这个order_input type?这也是出于学习目的,但我同意您的存储过程和交易建议。
    • 我尝试了您提出的更新解决方案,它给了我以下查询select * from insert_into_orders (array['{"item":"Red Widget","quantity”:10}’]::thought_input[]),但我再次收到{ "error": { "message": "malformed array literal: \"{\"item\":\"Red Widget\", \"quantity\":10}\"" } } 错误。我想知道是否是因为 sql 函数期望数据是列表的元组?有什么想法吗?
    • @Gus 试试额外的演员阵容?喜欢::json[]::order_input[]
    • 不幸的是,我无法让从对象到元组的转换工作。我只是使用字符串插值来使 orderInput 看起来像一个元组('Red Widget', 10), ('Blue Widget', 5),因为这是函数所期望的,并保留了你所有的其他建议。我真的很感谢所有的帮助。不知道你是谁,但要保持安全和健康。
    • 像@Gus 一样,不能让它与 json[] 演员一起工作,但只是在 array[...] 中使用vitaly 的values 助手来创建元组,然后转换为参数数组类型工作。所以替换为toPostgres: () => `array[${this.pgp.helpers.values(orderInput, ["item", "quantity"])}]::order_input[]`
    猜你喜欢
    • 2018-08-23
    • 2018-04-11
    • 2018-12-10
    • 1970-01-01
    • 2013-05-11
    • 2017-06-10
    • 1970-01-01
    • 2017-11-29
    • 2016-09-13
    相关资源
    最近更新 更多