たくさんあります 私は違ったやり方で、そして大きな効果をもたらすでしょう。
テーブル定義
テーブルの定義と命名規則から始めます。これらはほとんど単なる意見です:
CREATE TEMP TABLE conta (conta_id bigint primary key, ...);
CREATE TEMP TABLE departamento (
dept_id serial PRIMARY KEY
, master_id int REFERENCES departamento (dept_id)
, conta_id bigint NOT NULL REFERENCES conta (conta_id)
, nome text NOT NULL
);
主なポイント
-
bigserial
> 部門のために?この惑星にはそれほど多くはありません。プレーンなシリアル
十分なはずです。 -
文字の変化
を使用することはほとんどありません。 長さ制限あり。他のいくつかのRDBMSとは異なり、制限を使用してもパフォーマンスはまったく向上しません。CHECK
を追加します 本当に最大長を強制する必要がある場合は制約。テキスト
を使用しています 、主にそして、トラブルを回避します。 -
外部キー列が参照される列と名前を共有する命名規則を提案するので、
master_id
master_fk
の代わりに 、など。USING
の使用も許可されます 参加します。 -
そして、私はめったに わかりにくい列名
id
を使用します 。dept_id
の使用 代わりにここに。
PL/pgSQL関数
これは主に次のように簡略化できます。
CREATE OR REPLACE FUNCTION f_retornar_plpgsql(lista_ini_depts VARIADIC int[])
RETURNS int[] AS
$func$
DECLARE
_row departamento; -- %ROWTYPE is just noise
BEGIN
IF NOT EXISTS ( -- simpler in 9.1+, see below
SELECT FROM pg_catalog.pg_class
WHERE relnamespace = pg_my_temp_schema()
AND relname = 'tbl_temp_dptos') THEN
CREATE TEMP TABLE tbl_temp_dptos (dept_id bigint NOT NULL)
ON COMMIT DELETE ROWS;
END IF;
FOR i IN array_lower(lista_ini_depts, 1) -- simpler in 9.1+, see below
.. array_upper(lista_ini_depts, 1) LOOP
SELECT * INTO _row -- since rowtype is defined, * is best
FROM departamento
WHERE dept_id = lista_ini_depts[i];
CONTINUE WHEN NOT FOUND;
INSERT INTO tbl_temp_dptos VALUES (_row.dept_id);
LOOP
SELECT * INTO _row
FROM departamento
WHERE dept_id = _row.master_id;
EXIT WHEN NOT FOUND;
INSERT INTO tbl_temp_dptos
SELECT _row.dept_id
WHERE NOT EXISTS (
SELECT FROM tbl_temp_dptos
WHERE dept_id =_row.dept_id);
END LOOP;
END LOOP;
RETURN ARRAY(SELECT dept_id FROM tbl_temp_dptos);
END
$func$ LANGUAGE plpgsql;
電話:
SELECT f_retornar_plpgsql(2, 5);
または:
SELECT f_retornar_plpgsql(VARIADIC '{2,5}');
-
ALIAS FOR $ 1
は古い構文であり、推奨されていません 。代わりに関数パラメータを使用してください。 -
VARIADIC
パラメータを使用すると、呼び出しがより便利になります。関連: -
EXECUTE
は必要ありません 動的要素のないクエリの場合。ここで得られるものはありません。 -
テーブルを作成するために例外処理は必要ありません。マニュアルの引用
こちら : -
Postgres9.1以降には
CREATEがあります存在しない場合のTEMPテーブル
。 9.0の回避策を使用して、条件付きで一時テーブルを作成します。 -
Postgres 9.1は、
FOREACH
も提供します。 配列をループする 。
とは言うものの、ここに厄介な問題があります。これのほとんどは必要ありません。
rCTEを使用したSQL関数
Postgres 9.0でも、再帰CTE これを非常に簡単にします :
CREATE OR REPLACE FUNCTION f_retornar_sql(lista_ini_depts VARIADIC int[])
RETURNS int[] AS
$func$
WITH RECURSIVE cte AS (
SELECT dept_id, master_id
FROM unnest($1) AS t(dept_id)
JOIN departamento USING (dept_id)
UNION ALL
SELECT d.dept_id, d.master_id
FROM cte
JOIN departamento d ON d.dept_id = cte.master_id
)
SELECT ARRAY(SELECT DISTINCT dept_id FROM cte) -- distinct values
$func$ LANGUAGE sql;
同じ電話。
説明付きの密接に関連した回答: