【问题标题】:Call a Postgresql procedure with a ROWTYPE or RECORD literal使用 ROWTYPE 或 RECORD 文字调用 Postgresql 过程
【发布时间】:2020-10-02 11:12:17
【问题描述】:

我正在构建一个食谱书应用程序。我只是为了练习在 Postgresql 中工作:

postgres=# select version();
                                                 version                                                      
------------------------------------------------------------------------------------------------------------------
PostgreSQL 12.2 (Debian 12.2-2.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit
(1 row)


我有几个表用于存储基于配方的信息;一个与成分列表有关:

CREATE TABLE ingredient (
    id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    name TEXT NOT NULL,
    quantity NUMERIC NOT NULL,
    unit TEXT,
    display_order INT NOT NULL
);

我正在编写一个名为 save_recipe 的函数,目前看起来是这样的

CREATE OR REPLACE PROCEDURE save_recipe
  (
  first_name COOK.FIRST_NAME%TYPE,
  last_name COOK.LAST_NAME%TYPE,
  email COOK.EMAIL%TYPE,
  recipe_name RECIPE.NAME%TYPE,
  recipe_cook_time RECIPE.COOK_TIME%TYPE,
  recipe_preface RECIPE.PREFACE%TYPE,
  instructions RECIPE.INSTRUCTIONS%TYPE,
  ingred INGREDIENT
  )
AS $$
DECLARE
  cook_id COOK.ID%TYPE;
  recipe_id RECIPE.ID%TYPE;
BEGIN

  INSERT INTO cook (first_name, last_name, email)
    VALUES (first_name, last_name, email)
    RETURNING id INTO cook_id;

  INSERT INTO recipe (name, cook_id, created_at, cook_time, instructions, preface)
    VALUES (recipe_name, cook_id, now(), recipe_cook_time, instructions, recipe_preface)
    RETURNING id INTO recipe_id;

  INSERT INTO ingredient (name, quantity, unit, display_order)
    VALUES (ingred.name, ingred.quantity, ingred.unit, ingred.display_order);

  COMMIT;

  RAISE NOTICE 'Cook ID : %', cook_id;
  RAISE NOTICE 'Recipe ID : %', recipe_id;

END;
$$
LANGUAGE plpgsql;

但我在创建成分文字时遇到了问题(如果这是正确的词)。这是我目前能做的最好的:

CALL save_recipe(
  first_name => 'Joe',
  last_name => 'Fresh',
  email => 'joe@loblaws.com',
  recipe_name => 'Cherry Pie',
  recipe_cook_time => '1 hour',
  recipe_preface =>'I love cherry pie.',
  instructions => ARRAY['Make.', 'Bake.', 'Eat.'],
  ingred => (0, 'Cherry', 20, 'small, pitted', 1)
);

我希望 ingred 成为一个数组,但我更担心的是我需要填充 ingredient.id,即使我在插入过程中忽略了它(因为我想使用 Postgres 提供的生成的 ID )。有没有我可以使用的结构/类型,我不需要像这样指定一个虚拟 ID(最终可以是 ARRAY 类型)。

提前致谢。

【问题讨论】:

  • 我以前读过这个SO answer,但我希望有更好的东西。

标签: postgresql stored-procedures plpgsql postgresql-12


【解决方案1】:

将参数声明为类型的variadic array。使用unnest() 将数组元素获取为行(为了便于阅读,该函数已简化):

CREATE OR REPLACE PROCEDURE save_recipe
  (
  first_name text,
  last_name text,
  email text,
  VARIADIC ingred INGREDIENT[]
  )
AS $$
DECLARE
  cook_id COOK.ID%TYPE;
BEGIN

  INSERT INTO cook (first_name, last_name, email)
    VALUES (first_name, last_name, email)
    RETURNING id INTO cook_id;

  INSERT INTO ingredient (name, quantity, unit, display_order)
  SELECT i.name, i.quantity, i.unit, i.display_order
  FROM unnest(ingred) i;

  RAISE NOTICE 'Cook ID : %', cook_id;

END;
$$
LANGUAGE plpgsql;

使用示例:

CALL save_recipe(
    first_name => 'Joe',
    last_name => 'Fresh',
    email => 'joe@loblaws.com',
    variadic ingred => array[
        '(0, Apple, 2, small, 1)', 
        '(0, Pear, 5, large, 2)',
        '(0, Cherry, 20, "small, pitted", 1)'
    ]::ingredient[]
);

select *
from ingredient;

 id |  name   | quantity |      unit      | display_order
----+---------+----------+----------------+---------------
  1 |  Apple  |        2 |  small         |             1
  2 |  Pear   |        5 |  large         |             2
  3 |  Cherry |       20 |  small, pitted |             1
(3 rows)

请注意,如果没有命名参数,过程调用可能会简单得多:

CALL save_recipe(
    'Joe', 'Fresh', 'joe@loblaws.com',
    '(0, Apple, 2, small, 1)', 
    '(0, Pear, 5, large, 2)',
    '(0, Cherry, 20, "small, pitted", 1)'
);

Db<>fiddle.

【讨论】:

  • 这可能是我的错。我从我实际使用的代码中做了一个太简单的例子,我不确定VARIADIC 是否适用于我的情况(基于我刚刚阅读的内容)。我会更新问题。
  • 非常感谢您重新访问答案。对此,我真的非常感激。效果很好。
  • 我在将插入语句插入成分时遇到错误,但后来我意识到我没有对原始语句进行足够的更改。它必须是INSERT INTO...SELECT...FROM... 而不是INSERT INTO...VALUES...FROM...。再次感谢您。
猜你喜欢
  • 2016-04-17
  • 1970-01-01
  • 2016-03-15
  • 1970-01-01
  • 2017-02-08
  • 1970-01-01
  • 1970-01-01
  • 2020-08-18
  • 1970-01-01
相关资源
最近更新 更多