Postgresql
基於另一列中的值的列約束
我有一個 PostgreSQL 表
phase_steps
,具有以下範例行:phase_step_id|step_type|step_status| -------------+---------+-----------+ 1| RESEARCH| | 2| SURVEY| |
更新
step_status
列的值取決於該step_type
值是什麼值。當
step_type
是’RESEARCH’ 時,只能輸入’COMPLETE’ 或’INCOMPLETE’ 的值作為step_status
值。當
step_type
是“SURVEY”時,只能輸入“ASSIGNED”或“NOT ASSIGNED”的值作為step_status
值。我嘗試
step_status
使用以下過程管理“研究”約束:create or replace function insert_step_status_value() returns trigger as $$ begin if (new.step_status != 'COMPLETE') or (new.step_status != 'INCOMPLETE') from phase_steps where step_type = 'RESEARCH' then raise exception 'Status value not in range for this phase step'; end if; return new; end; $$ language plpgsql; create trigger check_step_status_value before update on phase_steps for each row execute procedure insert_step_status_value();
但是,像這樣的插入
update jobs.phase_steps set step_status_lu = 'INCOMPLETE' where phase_step_id = 1;
給出一個錯誤:
SQL Error [P0001]: ERROR: Status value not in range for this phase step Where: PL/pgSQL function insert_step_status_value() line 6 at RAISE
想法?
CHECK
約束應該完成這項工作。比任何觸發解決方案都更簡單、更便宜、更可靠:要僅強制執行列出的組合併仍然允許其他任何內容,您的表定義可能如下所示:
CREATE TABLE jobs.phase_steps ( phase_step_id integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY , step_type text , step_status text , CONSTRAINT step_status_for_step_type CHECK (step_type = 'RESEARCH' AND step_status IN ('COMPLETE', 'INCOMPLETE') OR step_type = 'SURVEY' AND step_status IN ('ASSIGNED', 'NOT ASSIGNED')) );
db<>在這裡擺弄
運算符優先級對我們有利,因此不需要額外的括號。不允許ans
有其他值。
step_type``step_status
定義約束有兩種方式:表約束和列約束。列約束被定義為列定義的一部分。表約束定義不綁定到特定列,它可以包含多個列。
這仍然允許
null
兩列中的值。如果CHECK
表達式產生true
or ,則傳遞約束null
。您必須定義在哪裡排除或允許這些。也許你只是想要兩列NOT NULL
?還要禁止 的任何其他值
step_type
:ALTER TABLE phase_steps DROP CONSTRAINT step_status_for_step_type , ADD CONSTRAINT step_status_for_step_type CHECK (CASE step_type WHEN 'RESEARCH' THEN step_status IN ('COMPLETE', 'INCOMPLETE') WHEN 'SURVEY' THEN step_status IN ('ASSIGNED', 'NOT ASSIGNED') ELSE false END)
step_type
現在(incl. ) 的任何其他值null
到達ELSE
分支並進行檢查false
。(但 NULL instep_status
仍然通過。)db<>在這裡擺弄