I am new to postgresql and am trying to update a table based on conditions using PostgreSQL stored procedure.
The table ‘pref2’ looks like this:
geneid pred_perf_r2 pred_perf_pval vers
ENSG00000107959 0.03 0.02 1.0
ENSG00000106321 0.05 0.01 1.0
ENSG00000102222 0.22 0.05 1.0
ENSG00000101111 0.11 0.03 1.0
ENSG00000102355 0.33 0.01 1.0
I want to create a stored procedure for updating this table for pred_perf_r2 and pred_perf_pval if the new scores are better (bigger R2 and smaller pval). My attempt:
create or replace procedure new_version(
gene varchar(50),
new_r2 numeric,
new_p numeric,
new_v numeric
)
language plpgsql
as $$
begin
if (new_r2 > perf2.pred_perf_r2)
and (new_p < perf2.pred_perf_pval) then
update perf2 set
perf2.pred_perf_r2 = new_r2,
perf2.pred_perf_pval = new_p ,
perf2.vers = new_v
where perf2.geneid = gene;
end if;
commit;
END;$$
call new_version('ENSG00000107959',0.55,0.01,2.0);
select * from perf2;
It gives me this error:
ERROR: missing FROM-clause entry for table "perf2"
LINE 1: (new_r2 > perf2.pred_perf_r2)
^
QUERY: (new_r2 > perf2.pred_perf_r2)
and (new_p < perf2.pred_perf_pval)
CONTEXT: PL/pgSQL function new_version(character varying,numeric,numeric,numeric) line 3 at IF
SQL state: 42P01
My desired result will look like this when calling the stored procedure:
geneid pred_perf_r2 pred_perf_pval vers
ENSG00000107959 0.55 0.01 2.0
ENSG00000106321 0.05 0.01 1.0
ENSG00000102222 0.22 0.05 1.0
ENSG00000101111 0.11 0.03 1.0
ENSG00000102355 0.33 0.01 1.0
if
call new_version('ENSG00000107959',0.02,0.05,2.0);
The original table should not change since R square is worse (0.02 < 0.03) and pval is larger (0.05>0.02)
It keeps giving me errors. Any ideas on how I can fix this?
2
Answers
The problem with your procedure is that you cannot guarantee nobody will bypass it by writing a regular
UPDATE
statement.You can solve this with a trigger or a rule.
Solution 1: Trigger
Solution 1 will raise an exception, which:
UPDATE
in the middle of a transaction).Code:
Solution 2: Rule
Solution 2 skips records breaking your rule and will not raise any error, which:
Code:
As the error states this,
perf2.pred_perf_r2
, is table reference for a table that does not exist in the function context. Same will happen withperf2.pred_perf_pval
. The other issue is that neither value is filtered to a specificgene
. Also you can’t table specify the updated columns so thisperf2.pred_perf_r2 = new_r2
needs to bepred_perf_r2 = new_r2
, same for the other columns. You would need to do something like:Option B. Put the
if
logic in theUPDATE
statement.