2つの履歴テーブルがあります。 1つは親で、2つ目は詳細です。この場合、別の表の変更を追跡する履歴表です。pl/pgsql親子テーブルとROWTYPEの配列を持つCTE挿入
CREATE TABLE IF NOT EXISTS history (
id serial PRIMARY KEY,
tablename text,
row_id integer,
ts timestamp,
username text,
source text,
action varchar(10)
);
CREATE TABLE IF NOT EXISTS history_detail (
id serial PRIMARY KEY,
master_id integer NOT NULL references history(id),
colname text,
oldval text,
newval text
);
次に、既存の行と新しい行を比較する関数があります。比較はまっすぐ私のように思える。私が苦労している部分は、私の履歴表に差を挿入したいときです。比較の間に私はhistory_detail
の配列に違いを格納していますが、当時私はIDまたは親テーブルの行が何であるか分かりません。それが私がハングアップしているところです。
CREATE OR REPLACE FUNCTION update_prescriber(_npi integer, colnames text[]) RETURNS VOID AS $$
DECLARE
t text[];
p text[];
pos integer := 0;
ts text;
updstmt text := '';
sstmt text := '';
colname text;
_id integer;
_tstr text := '';
_dtl history_detail%ROWTYPE;
_dtls history_detail[] DEFAULT '{}';
BEGIN
-- get the master table row id.
SELECT id INTO _id FROM master WHERE npi = _npi;
-- these select all the rows' column values cast as text.
SELECT unnest_table('tempmaster', 'WHERE npi = ''' || _npi || '''') INTO t;
SELECT unnest_table('master', 'WHERE npi = ''' || _npi || '''') INTO p;
-- go through the arrays and compare values
FOREACH ts IN ARRAY t
LOOP
pos := pos + 1;
-- pos + 1 becuse the master table has the ID column
IF p[pos + 1] != ts THEN
colname := colnames[pos];
updstmt := updstmt || ', ' || colname || '=t.' || colname;
sstmt := sstmt || ',' || colname;
_dtl.colname := colname;
_dtl.oldval := p[pos + 1];
_dtl.newval := ts;
_dtls := array_append(dtls, dtl);
RAISE NOTICE 'THERE IS a difference at for COLUMN %, old: %, new: %', colname, p[pos + 1], ts;
END IF;
END LOOP;
RAISE NOTICE 'dtls length: %', array_length(dtls,1);
RAISE NOTICE 'dtls: %', dtls;
RAISE NOTICE 'done comparing: %', updstmt;
IF length(updstmt) > 0 THEN
WITH hist AS (
INSERT INTO history
(tablename, row_id, ts, username, source, action)
VALUES
('master', _id, current_timestamp, 'me', 'source', 'update')
RETURNING *
), dtls AS (
SELECT hist.id_
INSERT INTO history_detail
--
-- this is where I am having trouble
--
;
_tstr := 'UPDATE master
SET ' || substr(updstmt,2) || '
FROM (SELECT ' || substr(sstmt,2) || ' FROM tempmaster WHERE npi = ''' || _npi || ''') AS t
WHERE master.id = ' || _id || ';';
EXECUTE _tstr;
END IF;
END;
$$ LANGUAGE plpgsql;
理想的な世界で私はこれをすべてステートメントで行うことができます。私は別のBEGIN..END
の中に包まれた複数のステートメントでそれを行うことができることを知っています。私は可能な限り効率的な方法でそれを行うことを確認したいと思います。私は動的なものを取り除く方法があるとは思わないが、私より賢い人が正しい方向に私を押し込むことができればうれしい。
ありがとうございました。