回答:
トリガーを使用します。
ベースとして使用できるコードを次に示します。UPDATEも処理する必要がある場合は、わずかな変更のみが必要です。
create table people
(
first_name varchar(20),
last_name varchar(20),
display_name varchar(40)
);
CREATE TABLE
CREATE OR REPLACE FUNCTION people_insert() RETURNS trigger AS '
BEGIN
NEW.display_name := NEW.first_name||'' ''||NEW.last_name;
RETURN NEW;
END;
' LANGUAGE plpgsql;
postgres=# CREATE FUNCTION
CREATE TRIGGER people_insert BEFORE INSERT OR UPDATE ON people FOR
EACH ROW EXECUTE PROCEDURE people_insert();
postgres=# CREATE TRIGGER
insert into people values ('Larry','Ellison');
postgres=# INSERT 0 1
postgres=# select * from people;
first_name | last_name | display_name
------------+-----------+---------------
Larry | Ellison | Larry Ellison
(1 row)
postgres=#
CREATE TRIGGER people_insert BEFORE INSERT OR UPDATE...
は更新も処理しませんか?
実際に値を保存する必要はありません。生成された列のように参照できる関数を作成できます。1つの注意点は、参照は常にテーブル名またはエイリアス名で修飾する必要があるということです。
CREATE TABLE person
(
id int PRIMARY KEY,
first_name text,
last_name text NOT NULL
);
INSERT INTO person
VALUES
(1, 'John', 'Smith'),
(2, 'Jane', 'Doe'),
(3, NULL, 'Prince');
CREATE FUNCTION display_name(rec person)
RETURNS text
STABLE
LANGUAGE SQL
COST 5
AS $$
SELECT
CASE
WHEN $1.first_name IS NULL THEN ''
ELSE $1.first_name || ' '
END || $1.last_name;
$$;
SELECT p.id, p.display_name FROM person p;
結果:
id | 表示名 ---- + -------------- 1 | ジョンスミス 2 | ジェーン・ドウ 3 | 王子 (3行)
トリグラムの類似性に基づいてKNN検索を使用するなど、生成された値にインデックスを付けることもできます。例えば:
CREATE EXTENSION pg_trgm;
CREATE INDEX person_trgm_name
ON person
USING gist
(display_name(person) gist_trgm_ops);
SELECT
p.id,
p.display_name,
similarity(p.display_name, 'Jane')
FROM person p
ORDER BY p.display_name <-> 'Jane'
LIMIT 2;
このタイプの検索は、検索文字列からの「距離」の順序でインデックススキャンから行を返します。それらがどれだけ「近い」かを見たい場合は、距離演算子(<->
)またはsimilarity()
関数(1-距離)を使用できます。KNN検索は、非常に大きなデータセットがある場合でも、Kの「最近傍」を非常に迅速に返すことができます。
last_name
しNOT NULL
ました。:-)テーブルにあり、トリガーによって維持され、このアプローチにそれほど苦労せずに切り替えたような名前の列がありましたが、フレームワークは常にエイリアスを使用し、常に参照を修飾するため、その部分は簡単でした。カラム参照の修飾について一貫性のないコードがある場合、これらのすべてのケースを追跡するのが苦痛になる可能性があることがわかります。