列のデフォルト値を他の2つの列の値の連結に設定しますか?


13

Postgresql 8.1データベースがあります。一つのテーブルでは、3つの列がありますfirst_namelast_namedisplay_name

これは、デフォルト値の設定が可能であるdisplay_nameことにはfirst_name + " " + last_name


これは7年以上前の投稿です。しかし、好奇心をそそるために、このケースではビューを使用すべきではありませんか?更新、ストアのオーバーヘッド、トリガーなどは必要ありませんか?
厳しい

回答:


15

トリガーを使用します。

ベースとして使用できるコードを次に示します。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...は更新も処理しませんか?
-MattSayar

そうそう。半分眠っていたに違いありません:)
Philᵀᴹ12年

気にするなら、display_nameはおそらく41であるべきです。2つの20文字の列の間にスペースを追加するため。
isaaclw 14

このソリューションは、挿入操作に約15%のオーバーヘッドを追加することが
わかり

17

実際に値を保存する必要はありません。生成された列のように参照できる関数を作成できます。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の「最近傍」を非常に迅速に返すことができます。


実際には、後方互換性のために値を保存する必要がありますが、これはかなりクールなアプローチです!私のOCD担当者もNULLの姓のチェックを望んでいますが、それはおそらくその時点でより大きなデータ整合性の問題があることを意味するでしょう
-MattSayar

まあ、私は私の例にいると宣言last_nameNOT NULLました。:-)テーブルにあり、トリガーによって維持され、このアプローチにそれほど苦労せずに切り替えたような名前の列がありましたが、フレームワークは常にエイリアスを使用し、常に参照を修飾するため、その部分は簡単でした。カラム参照の修飾について一貫性のないコードがある場合、これらのすべてのケースを追跡するのが苦痛になる可能性があることがわかります。
kgrittn

2

列テーブルのデフォルト設定では、いいえ。

ここでの最善策は、計算する各列の新しい値を持つトリガーです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.