I have a PostgreSQL table phase_steps
, with the following example rows:
phase_step_id|step_type|step_status|
-------------+---------+-----------+
1| RESEARCH| |
2| SURVEY| |
Update values to the step_status
column depend on what value the
step_type
value is.
When step_type
is 'RESEARCH', only values of 'COMPLETE' or 'INCOMPLETE' can be entered for step_status
values.
When step_type
is 'SURVEY', only values of 'ASSIGNED' or 'NOT ASSIGNED' can be entered for step_status
values.
I tried to manage the 'RESEARCH' step_status
constraints with this procedure:
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();
However, an insert like
update jobs.phase_steps
set step_status_lu = 'INCOMPLETE'
where phase_step_id = 1;
gives an error:
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
Thoughts?
Best Answer
A
CHECK
constraint does the job. Simpler, cheaper and more reliable than a trigger.To enforce the listed combinations, your table definition could look like this:
Or a simpler equivalent:
fiddle
The manual:
Operator precedence works in our favor, no additional parentheses required.
Allows no other combined values for
(step_type, step_status)
- except fornull
values. ACHECK
constraint is passed if the expression evaluates totrue
ornull
.You may want to add a
NOT NULL
constraint tostep_type
, thenstep_status
can still benull
, andstep_type
can be anything (butnull
) in this case. But ifstep_status
has a value, the combination has to pass the check.Or, to also disallow any other value for
step_type
:Now any other value for
step_type
(incl.null
) reaches theELSE
branch and makes the checkfalse
. (Butnull
instep_status
still passes.)fiddle