我有一个这种形式的 PostgreSQL 表:
base_id int | mods smallint[]
3 | {7,15,48}
我需要填充这种形式的表格:
combo_id int | base_id int | mods smallint[]
1 | 3 |
2 | 3 | {7}
3 | 3 | {7,15}
4 | 3 | {7,48}
5 | 3 | {7,15,48}
6 | 3 | {15}
7 | 3 | {15,48}
8 | 3 | {48}
我想我可以使用一个几乎完全完成此操作的函数来完成此操作,迭代第一个表并将组合写入第二个表: 在 SQL 中生成所有组合
但是,我是 Postgres 新手,我一辈子都无法弄清楚如何使用 plpgsql 来做到这一点。它不需要特别快;它只会在后端定期运行。第一个表大约有 80 条记录,粗略计算表明我们可以预期第二个表大约有 2600 条记录。
谁能至少指出我正确的方向?
编辑:克雷格:我有 PostgreSQL 9.0。我成功地使用了 UNNEST():
FOR messvar IN SELECT * FROM UNNEST(mods) AS mod WHERE mod BETWEEN 0 AND POWER(2, @n) - 1
LOOP
RAISE NOTICE '%', messvar;
END LOOP;
但后来不知道下一步该去哪里。
编辑:作为参考,我最终使用了 Erwin 的解决方案,添加了一行以向每个集合添加空结果 ('{}'),并且 Erwin 所指的特殊情况已删除:
CREATE OR REPLACE FUNCTION f_combos(_arr integer[], _a integer[] DEFAULT '{}'::integer[], _z integer[] DEFAULT '{}'::integer[])
RETURNS SETOF integer[] LANGUAGE plpgsql AS
$BODY$
DECLARE
i int;
j int;
_up int;
BEGIN
IF array_length(_arr,1) > 0 THEN
_up := array_upper(_arr, 1);
IF _a = '{}' AND _z = '{}' THEN RETURN QUERY SELECT '{}'::int[]; END IF;
FOR i IN array_lower(_arr, 1) .. _up LOOP
FOR j IN i .. _up LOOP
CASE j-i
WHEN 0,1 THEN
RETURN NEXT _a || _arr[i:j] || _z;
ELSE
RETURN NEXT _a || _arr[i:i] || _arr[j:j] || _z;
RETURN QUERY SELECT *
FROM f_combos(_arr[i+1:j-1], _a || _arr[i], _arr[j] || _z);
END CASE;
END LOOP;
END LOOP;
ELSE
RETURN NEXT _arr;
END IF;
END;
$BODY$
然后,我使用该函数来填充我的表:
INSERT INTO e_ecosystem_modified (ide_ecosystem, modifiers)
(SELECT ide_ecosystem, f_combos(modifiers) AS modifiers FROM e_ecosystem WHERE ecosystemgroup <> 'modifier' ORDER BY ide_ecosystem, modifiers);
从我的源表中的 79 行和修饰符数组中最多 7 个项目开始,查询花费了 250 毫秒来填充我的输出表中的 2630 行。极好的。