I'm wondering if I can run the if statement by itself, or it can't stand on its own, has to be in a nested statement. I can't directly run the following code.
IF tax_year=2005 THEN
UPDATE table1 SET column1=column1*3;
ELSIF tax_year=2006 THEN
UPDATE table1 SET column1=column1*5;
ELSIF tax_year=2007 THEN
UPDATE table1 SET column1=column1*7;
END IF;
Also, I didn't write it out that when tax_year=2008, column1=column1. I'm not sure if it needs to be in the code since column1 won't change in 2008.
Thanks for your help!
IF / ELSIF / ELSE is part of PL/pgsql, which is an extension of pg, and it's enabled for new database by default.
You can create a function to wrap the IF statements. And call the function to execute these statements.
e.g
-- create function,
CREATE OR REPLACE FUNCTION fun_dummy_tmp(id_start integer, id_end integer) RETURNS setof dummy AS $$
DECLARE
BEGIN
IF id_start <= 0 THEN
id_start = 1;
END IF;
IF id_end < id_start THEN
id_end = id_start;
END IF;
return query execute 'select * from dummy where id between $1 and $2' using id_start,id_end;
return;
END;
$$ LANGUAGE plpgsql;
-- call function,
select * from fun_dummy_tmp(1, 4);
-- drop function,
DROP FUNCTION IF EXISTS fun_dummy_tmp(integer, integer);
And, there is a CASE statement, which might be a better choice for your requirement.
e.g
-- create function,
CREATE OR REPLACE FUNCTION fun_dummy_tmp(id integer) RETURNS varchar AS $$
DECLARE
msg varchar;
BEGIN
CASE id%2
WHEN 0 THEN
msg := 'even';
WHEN 1 THEN
msg := 'odd';
ELSE
msg := 'impossible';
END CASE;
return msg;
END;
$$ LANGUAGE plpgsql;
-- call function,
select * from fun_dummy_tmp(6);
-- drop function,
DROP FUNCTION IF EXISTS fun_dummy_tmp(integer);
You can refer to postgresql document for control statement for the details.
I did it with the following code:
-- UPDATE houston_real_acct_1single1property
-- SET convert_market_value=
-- CASE
-- WHEN tax_year=2005 THEN total_market_value*1.21320615034169
-- WHEN tax_year=2006 THEN total_market_value*1.17961794019934
-- WHEN tax_year=2007 THEN total_market_value*1.15884093604151
-- WHEN tax_year=2008 THEN total_market_value*1.12145267335906
-- WHEN tax_year=2009 THEN total_market_value*1.11834431349904
-- WHEN tax_year=2010 THEN total_market_value*1.0971664297633
-- WHEN tax_year=2011 THEN total_market_value*1.06256515125065
-- WHEN tax_year=2012 THEN total_market_value*1.04321957955664
-- WHEN tax_year=2013 THEN total_market_value*1.02632796014915
-- WHEN tax_year=2014 THEN total_market_value*0.998472101797389
-- WHEN tax_year=2015 THEN total_market_value
-- END;
Related
I am creating a function that allow me to conditionally update specific columns in a table. However, I get an error indicating that there is a syntax error at or near "IF" when I try to run the following code. I'm a bit new to Postgres so it's quite possible. I can't understand some concept/syntax thing in Postgres. Can someone help me by pointing out the mistake I must be making?
CREATE OR REPLACE FUNCTION profiles.do_something(
p_id UUID,
p_condition1 BOOLEAN,
p_condition2 BOOLEAN,
p_condition3 BOOLEAN
)
RETURNS void AS $$
BEGIN
IF p_condition1 IS TRUE THEN
UPDATE tablename SET column1 = null WHERE member_id = p_id;
END IF;
IF p_condition2 IS TRUE THEN
UPDATE tablename SET column2 = null WHERE member_id = p_id;
END IF;
IF p_condition3 IS TRUE THEN
UPDATE tablename SET column3 = null WHERE member_id = p_id;
END IF;
END;
$$ LANGUAGE 'sql';
tl;dr $$ LANGUAGE 'plpgsql'
$$ LANGUAGE 'sql';
^^^^^
You're tell it to parse the body of the function as sql. In SQL, begin is a statement which starts a transaction.
create or replace function test1()
returns void
language sql
as $$
-- In SQL, begin starts a transaction.
-- note the ; to end the statement.
begin;
-- Do some valid SQL.
select 1;
-- In SQL, end ends the transaction.
end;
$$;
In SQL you wrote begin if ... which is a syntax error.
The language you're using is plpgsql. In plpgsql, begin is a keyword which starts a block.
create or replace function test1()
returns void
language plpgsql
as $$
-- In PL/pgSQL, begin starts a block
-- note the lack of ;
begin
-- Do some valid SQL.
select 1;
-- In PL/pgSQL, end ends the block
end;
$$;
I am new to using postgresql, I am trying to make a trigger that just inserts in the Employee table and also inserts in the Vacations table, but I don't know how to assign the values, I do it like that in sql but here I really don't know how
CREATE FUNCTION SP_InsertaVacacionesEmpleado() RETURNS TRIGGER
AS
$$
DECLARE _NumeroIdentificacion INTEGER;
DECLARE _FechaEntrada DATE;
BEGIN
SET _NumeroIdentificacion = SELECT NEW.NumeroIdentificacion FROM "Empleado"
SET _FechaEntrada = SELECT NEW.FechaEntrada FROM "Empleado"
INSERT INTO Vacaciones VALUES(_NumeroIdentificacion, _FechaEntrada, '', 0);
RETURN NEW;
END
$$
LANGUAGE plpgsql
As documented in the manual assignment is done using the := operator, e.g.:
some_variable := 42;
However to assign one or more variables from the result of a query, use select into, e.g.:
DECLARE
var_1 INTEGER;
var_2 DATE;
BEGIN
select col1, col2
into var_1, var_2
from some_table
...
However neither of that is necessary in a trigger as you can simply use the reference to the NEW record directly in the INSERT statement:
CREATE FUNCTION sp_insertavacacionesempleado()
RETURNS TRIGGER
AS
$$
BEGIN
INSERT INTO Vacaciones (...)
VALUES (NEW.NumeroIdentificacion, NEW.FechaEntrada , '', 0);
RETURN NEW;
END
$$
LANGUAGE plpgsql;
Note that you need to define a row level trigger for this to work:
create trigger ..
before insert on ...
for each row --<< important!
execute procedure sp_insertavacacionesempleado() ;
This is what I'd like to achieve:
CREATE FUNCTION f() RETURNS trigger AS $$
BEGIN
SELECT COUNT(*) AS total_num, SUM(width) AS total_width
FROM some_table WHERE foo = NEW.foo;
IF total_num > 0 AND total_width > 100
THEN
RAISE EXCEPTION 'this is bad';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
But it's not yet syntactically correct.
I've read I first need to DECLARE the variables (in this case total_num and total_width) so I can use those and use SELECT INTO but I've seen examples with a single variable / SELECT statement only. What if I have more of them?
You can list multiple variables in the into part. And the declare section needs to come before the first begin:
CREATE FUNCTION f() RETURNS trigger
AS $$
declare
total_num bigint;
total_width bigint;
BEGIN
SELECT COUNT(*), SUM(width)
into total_num, total_width
FROM some_table
WHERE foo = NEW.foo;
IF total_num > 0 AND total_width > 100 THEN
RAISE EXCEPTION 'this is bad';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Edit: I'm not sure whether the emphasis here is on the use of variables or the actual IF. This is meant as an answer on the latter:
You can do this without variables using HAVING and EXISTS.
IF EXISTS (SELECT ''
FROM some_table
WHERE foo = new.foo
HAVING count(*) > 0
AND sum(width) > 100) THEN
RAISE EXCEPTION 'this is bad';
END IF;
After reading the documentation for ASSERT, I am still confused how to use it, and can't find any examples online of how I would do something simple using ASSERT in a .sql script.
For example, say I want to ASSERT that the number of rows returned from SELECT * FROM my_table WHERE my_col = 3 is equal to 10.
Can someone provide a working example of that?
I would assume you try todo smth similar?
so=# select count(*) from pg_database;
count
-------
21
(1 row)
so=# do $$ begin assert (select count(*) from pg_database) = 21, 'not 21!';end;$$;
DO
so=# do $$ begin assert (select count(*) from pg_database) = 22, 'not 22!';end;$$;
ERROR: not 22!
CONTEXT: PL/pgSQL function inline_code_block line 1 at ASSERT
do $$
begin
ASSERT 1 = 2;
end;
$$ LANGUAGE plpgsql;
But note, it works only starting from PostgreSql 9.5. In older versions you can define your own assert-function such like this
CREATE OR REPLACE FUNCTION __assert(boolean) RETURNS VOID AS $$
BEGIN
IF NOT $1 THEN
RAISE EXCEPTION 'ASSERTING FAILED';
END IF;
END;
$$ LANGUAGE plpgsql;
And then use in this way
do $$
declare
tmp char;
begin
tmp := __assert(tmp_to_https('https') = 'https');
end;
$$ LANGUAGE plpgsql;
I have a simple mission is inserting huge MD5 values into tables (partitioned table), and have created a trigger and also a trigger function to instead of INSERT operation. And in function I checked the first two characters of NEW.md5 to determine which table should be inserted.
DECLARE
tb text;
BEGIN
IF TG_OP = 'INSERT' THEN
tb = 'samples_' || left(NEW.md5, 2);
EXECUTE(format('INSERT INTO %s VALUES (%s);', tb, NEW.*)); <- WRONG
END IF;
RETURN NULL;
END;
The question is how to concat the NEW.* into the SQL statement?
Best with the USING clause of EXECUTE:
CREATE FUNCTION foo ()
RETURNS trigger AS
$func$
BEGIN
IF TG_OP = 'INSERT' THEN
EXECUTE format('INSERT INTO %s SELECT $1.*'
, 'samples_' || left(NEW.md5, 2);
USING NEW;
END IF;
RETURN NULL;
END
$func$ LANGUAGE plpgsql;
And EXECUTE does not require parentheses.
And you are aware that identifiers are folded to lower case unless quoted where necessary (%I instead of %s in format()).
More details:
INSERT with dynamic table name in trigger function
How to dynamically use TG_TABLE_NAME in PostgreSQL 8.2?