Im using "else" inside a case operator to declare a value into a variable through the value in a record.
Im trying to declare a value like that:
DO $$
DECLARE
rec_pessoa record;
num_categoria_pessoa integer;
BEGIN
FOR rec_pessoa IN SELECT * FROM pessoas LOOP
num_categoria_pessoa = CASE rec_pessoa.cliente_tipo_clt_id
WHEN 2 THEN 7
WHEN 6 THEN 3
WHEN 13 THEN 1
WHEN 114 THEN 37
ELSE NULL;
END;
-- (...)
But getting this error:
psql:pessoas_table/3_transf.sql:414: ERROR: syntax error at or near "THEN"
LINE 22: ELSE THEN NULL;
Related
I am trying to use a function to update a column on a table by creating a function that will do it.
I am trying to create a customer tier based on purchases made by each customer. I know the following code will update my column when I run the command by itself:
update email_campaign_detailed
set customer_tier = 'standard'
where num_dvd_rented <=20;
However I want to use a function to do this so I can input the data and have it auto-rank.
this is the code I'm using that isn't working:
Create or replace function customer_tier(num_dvds_rented bigint)
Returns character varying (50)
Language plpgsql
As
$$
Declare
Begin
case
when num_dvd_rented <=20 then update email_campaign_detailed set customer_tier ='standard'
when num_dvd_rented >= 21 and <= 39 then update email_campaign_detailed set customer_tier ='silver'
else update email_campaign_detailed set customer_tier ='gold'
End case;
end;
$$
I get a syntax error at the second "when" statement.
I cannot for the life of me figure out what I need to do.
Any help or insight is deeply appreciated.
Thanks!
You don't need a stored procedure when using the case-expression. Because case is an expression, you can just use it in your sql-statement (like any other expression):
update email_campaign_detailed
set
customer_tier = case
when num_dvd_rented <= 20 then 'standard'
when num_dvd_rented >= 21 and <= 39 then 'silver'
else 'gold'
end
where num_dvd_rented <= 20;
==== EDIT ===
Your stored procedure doesn't work because you can't have an expression (an update statement) within your when branches.
I suppose you want to use the num_dvds_rented parameter in the stored procedure for your where statement?
create or replace function customer_tier(num_dvds_rented bigint)
language plpgsql
As
$$
declare
begin
update email_campaign_detailed
set
customer_tier = case
when num_dvd_rented <= 20 then 'standard'
when num_dvd_rented >= 21 and <= 39 then 'silver'
else 'gold'
end
where num_dvd_rented <= num_dvds_rented;
end;
$$
Also, your stored procedure doesn't really return anything -- so you don't need the returns... in the declaration.
Now, if your goal is to do something like this:
update email_campaign_detailed
set customer_tier = customer_tier(num_dvd_rented)
where num_dvd_rented <= 20;
then your procedure might look like this:
create or replace function customer_tier(num_dvds_rented bigint)
returns character varying (50)
language plpgsql
As
$$
declare
begin
return case
when num_dvds_rented <= 20 then 'standard'
when num_dvds_rented >= 21 and <= 39 then 'silver'
else 'gold'
end;
end;
$$
Proof you can have expressions in the CASE branches. You just need to terminate then with a ;.
CREATE OR REPLACE FUNCTION public.case_test()
RETURNS void
LANGUAGE plpgsql
AS $function$
DECLARE
int_val integer;
BEGIN
CASE WHEN 1 = 1 THEN
select 1 into int_val;
ELSE
select 3 into int_val;
END CASE;
RAISE NOTICE 'Val is %', int_val;
END;
$function$
;
select case_test();
NOTICE: Val is 1
case_test
-----------
This is a working function in SQL Server 2014 Express
CREATE FUNCTION [dbo].[Func_Account_FollowingCustomer]
(#AccountNumber NVARCHAR(20))
RETURNS BIT
AS
BEGIN
DECLARE #bResult BIT
IF (SELECT COUNT(AccountNumber) FROM dbo.Account AS A
WHERE DetailByAccountObject = 1
AND AccountObjectType = 1
AND AccountNumber = #AccountNumber) > 0
SET #bResult = 1
ELSE
SET #bResult = 0
RETURN #bResult
END
I try to convert to PostgreSQL 14, I have
CREATE FUNCTION public.func_account_following_customer(IN account_number character varying)
RETURNS bit
LANGUAGE 'sql'
declare #b_result bit
begin
if(select count(account_number) from account as a where detail_by_account_object = 1 and account_object_type = 1 and account_number = #account_number) > 0
set #b_result = 1
else
set #b_result = 0
return #b_result;
end;
ALTER FUNCTION public.func_account_following_customer(character varying)
OWNER TO postgres;
Error
ERROR: syntax error at or near "declare" LINE 5: declare #b_result bit ^
How to fix it?
language sql can't use variables or procedural elements (like IF), you need language plpgsql - but the syntax for variable names is different and the assignment is not done using set
The function body is a string constant, typically specified using dollar quoting.
If you want to return true/false flags, use boolean instead of bits.
Parameters or variables are referenced using # but simply with their name.
But you don't need procedural code for such a simple SQL query that just returns true/false.
CREATE FUNCTION public.func_account_following_customer(IN p_account_number character varying)
RETURNS boolean
LANGUAGE sql
as
$$
select count(*) > 0
from account as a
where detail_by_account_object = 1
and account_object_type = 1
and account_number = p_account_number;
$$
;
As a PL/pgSQL function this would be:
CREATE FUNCTION public.func_account_following_customer(IN p_account_number character varying)
RETURNS boolean
LANGUAGE plpgsql
as
$$
declare
l_result boolean;
begin
if (select count(*)
from account as a
where detail_by_account_object = 1
and account_object_type = 1
and account_number = p_account_number) > 0
then
l_result := true;
else
l_result := false;
end if;
return l_result;
end;
$$
;
create or replace function f1() //procedure should display 9
returns void
as $$
declare age int default 9; //variable declaration
begin
select age; //prints 9
end;
$$ language plpgsql;
CREATE FUNCTION
I keep receiving this error
perform f1();
ERROR: syntax error at or near "perform"
LINE 1: perform f1();
perform is a PL/pgSQL statement. In plain SQL, you simply use SELECT:
select f1();
Note that the function as written, will not "print 9" - it will result in an error as the result of a SELECT needs to be stored somewhere. In PL/pgSQL you would need the RAISE statement to "print" something:
create or replace function f1()
returns void
as $$
declare
age int default 9;
begin
raise 'Age: ', age; -- this prints 9
end;
$$
language plpgsql;
If you want a function to "display" something, it might make more sense to let the function return a result:
create or replace function f1()
returns int
as $$
declare
age int default 9;
begin
return age;
end;
$$
language plpgsql;
Then select f1() will "print" 9
Is there an equivalent (or workaround) for the RAISE EXCEPTION statement for the function written below in LANGUAGE sql?
CREATE OR REPLACE FUNCTION fn_interpolation (p_yearinteger integer,
p_admin_id integer, p_crop_id integer, p_cropparameter integer)
RETURNS TABLE (value double precision, remark text)
AS $$
WITH
yearvalues AS (SELECT yearinteger, value FROM cropvalues WHERE crops_id =
p_crop_id AND admin_id = p_admin_id AND parameter_id = p_cropparameter),
I need the function to abort and to RETURN an error message if the arguments entered into the function do not exist. e.g. IF parameter_id != p_cropparameter THEN RAISE EXCEPTION ‘invalid cropparameter’ END IF
Just define a trivial wrapper function.
CREATE OR REPLACE FUNCTION raise_exception(text) RETURNS text AS $$
BEGIN
RAISE EXCEPTION '%',$1;
END;
$$ LANGUAGE plpgsql VOLATILE;
then use CASE:
SELECT CASE
WHEN parameter_id != p_cropparameter
THEN raise_exception("blah")
ELSE parameter_id
END;
This only works if the CASE otherwise returns text though, e.g. if parameter_id is integer you get:
regress=> SELECT CASE WHEN 1 = 2 THEN raise_exception('blah') ELSE 1 END;
ERROR: CASE types integer and text cannot be matched
LINE 1: SELECT CASE WHEN 1 = 2 THEN raise_exception('blah') ELSE 1 E...
You can work around this with a hack using polymorphic functions. Define:
CREATE OR REPLACE FUNCTION raise_exception(anyelement, text) RETURNS anyelement AS $$
BEGIN
RAISE EXCEPTION '%',$2;
RETURN $1;
END;
$$ LANGUAGE plpgsql VOLATILE;
then pass a fake value of the case type to it so PostgreSQL type-matches it correctly, e.g.
SELECT CASE WHEN 1 = 1 THEN raise_exception(0, 'blah') ELSE 1 END;
or
SELECT CASE WHEN 1 = 1 THEN raise_exception(NULL::integer, 'blah') ELSE 1 END;
All seem too hard? That's because really, this sort of thing is usually just better done in PL/PgSQL.
raise_exception.sql
Function to throwing an error for unhandled/impossible value.
Uses in SQL language.
Wrapper for RAISE command with EXCEPTION level in PL/pgSQL language.
Tests and using examples are included.
I want to insert records to a table by function.
CREATE OR REPLACE FUNCTION insert_wilda()
RETURNS integer AS
$BODY$
DECLARE
countKab integer;
i integer;
BEGIN
i := 1;
SELECT count(*)+34 into countKab from m_kab
WHILE (i <= countKab)
loop
INSERT INTO "t_historyWilda"("kdHistory","kdProp","kdKab","kdKec","nmWilda","noUrut",bulan,tahun,"isActive")
SELECT 'i',"kdProp","kdKab",'000',"namaKab",'1', EXTRACT(MONTH FROM TIMESTAMP 'now()'), EXTRACT(YEAR FROM TIMESTAMP 'now()'),'1' FROM m_kab
end loop;
RETURN i;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
But I got error like this:
ERROR: syntax error at or near "<="
LINE 10: WHILE (i <= countKab)
^
********** Error **********
ERROR: syntax error at or near "<="
You missed ';' after this line
SELECT count(*)+34 into countKab from m_kab