将 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;
我有一个 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;