将 Get/Create 存储过程从一项概括为多项

Generalize Get/Create Stored Procedure From One Item to Many

我有一个 express.js 服务器 运行 一个应用程序,我可以从该服务器使用存储过程在 PostgreSQL(版本 11)中访问或创建 "variant_id"s。

SELECT(get_or_create_variant_id(info_about_variant));

有时我还需要通过使用不同的存储过程来取回这些变体 ID,该存储过程采用多个变体和 returns 多个 ID。

SELECT(get_or_create_variant_ids([info_about_variant, info_about_another_variant]));

将 getting/creating 单个 ID 泛化为同时执行多个 ID 的最佳方法是什么?我在存储过程的循环中处理它,但感觉我应该可以使用 JOIN 代替。

CREATE OR REPLACE FUNCTION get_or_create_variant_id(
  variant_in VARIANT_TYPE
) RETURNS INT AS $$
DECLARE variant_id_out INTEGER;
BEGIN
  -- I'll be changing this to a ON CONFLICT block shortly
  SELECT(get_variant_id(variant_in) INTO variant_id_out);
  IF (variant_id_out IS NOT NULL) THEN
    RETURN variant_id_out;
  ELSE
    INSERT INTO public.variant (
        [some_fields]
    )
      VALUES (
        [some_values]
      )
      RETURNING variant_id INTO variant_id_out;
    RETURN variant_id_out;
  END IF;
END;
$$ LANGUAGE plpgsql;

-- What is the best way to avoid a loop here?
CREATE OR REPLACE FUNCTION get_or_create_variant_ids(
  variants_in VARIANT_TYPE []
) RETURNS INT [] AS $$
DECLARE variant_ids_out INTEGER [];
DECLARE variants_in_length INTEGER;
DECLARE current_variant_id INTEGER;
BEGIN
  SELECT (array_length(variants_in, 1) INTO variants_in_length);
  FOR i IN 1..variants_in_length LOOP
    SELECT(get_or_create_variant_id(variants_in[i]) INTO current_variant_id);
    SELECT(array_append(variant_ids_out, current_variant_id) INTO variant_ids_out);
  END LOOP;
  RETURN variant_ids_out;
END;
$$ LANGUAGE plpgsql;

-- Everything below is included for completeness, but probably less relevant to my question.
CREATE TYPE variant_type AS (
   [lots of info about the variant]
);
CREATE OR REPLACE FUNCTION get_variant_id(
  variant_in VARIANT_TYPE
) RETURNS INT AS $$
DECLARE variant_id_out INTEGER;
BEGIN
  SELECT variant_id into variant_id_out
  FROM public.variant
  WHERE
     [I want them to]
  ;
  RETURN variant_id_out;
END;
$$ LANGUAGE plpgsql;

您可以使用内置 array functions - in this case, unnest function, and array constructor 来避免显式循环。

CREATE OR REPLACE FUNCTION get_or_create_variant_ids_v2(
  variants_in VARIANT_TYPE []
)
RETURNS integer []
LANGUAGE sql AS $$
  SELECT ARRAY(
    SELECT get_or_create_variant_id(u.v)
    FROM unnest(variants_in) AS u(v)
  )
$$ LANGUAGE sql;