Postgresql Simple IF ELSE Statement - postgresql

In MS SQL I can execute a statement like:
Declare #foo int = 1, #foo1 int = 42
IF #foo <> 0
BEGIN
SELECT #foo
END
ELSE
BEGIN
SELECT #foo, #foo1
END
Does anyone have any idea how to run this statement on postgresql?
EDIT: MS SQL Example like :
CREATE PROCEDURE dbo.spIFtest
#p1 int = 1,
#p2 int = 10,
#isFilter bit = 0
AS
BEGIN
IF #isFilter = 1
BEGIN
SELECT idx FROM rw.octest where idx between #p1 and #p2
END
ELSE
BEGIN
SELECT idx FROM rw.octest
END
END
GO

Using DO With caveats:
DO $$
DECLARE
foo integer := 1;
foo1 integer := 42;
BEGIN
IF foo <> 0 THEN
PERFORM foo;
ELSE
PERFORM foo, foo1;
END IF;
END;
$$
;
DO cannot return anything.
You can fake a return:
DO $$
DECLARE
foo integer := 0;
foo1 integer := 42;
BEGIN
IF foo <> 0 THEN
SELECT INTO foo 1;
RAISE NOTICE 'foo is %', foo;
ELSE
SELECT INTO foo, foo1 1, 42 ;
RAISE NOTICE 'foo is %, foo1 is %', foo, foo1;
END IF;
END;
$$
;
NOTICE: foo is 1, foo1 is 42
DO

In PostgreSQL DO Block can execute the queries but they can not return any value.
So the first part of your question is not possible directly in postgresql.
For second part of your question: In PostgreSQL you can use Function (which is very powerful and effective) like below:
create or replace function spiftest()
returns table(idx_ int)
as $$
declare
p1 int := 1;
p2 int := 10;
isfilter boolean := 0;
begin
if isfilter then
return query
SELECT idx FROM octest where idx between p1 and p2;
else
return query
SELECT idx FROM octest ;
end if;
end;
$$
language plpgsql
calling above function for result:
select * from spiftest()
You can write it with parameters also like below:
create or replace function spiftest(p1 int, p2 int, isfilter boolean)
returns table(idx_ int)
as $$
begin
if isfilter then
return query
SELECT idx FROM octest where idx between p1 and p2;
else
return query
SELECT idx FROM octest ;
end if;
end;
$$
language plpgsql
to call above function
select * from spiftest(1,10,'t')

Related

Postgresql howto dynamically change parameter value

Is it possible to dynamically set param of numeric() ? eg:
CREATE OR REPLACE somefunction() RETURNS numeric AS
DECLARE
f numeric;
x integer;
BEGIN
x := 2;
SELECT INTO f CAST(something AS numeric(12, x));
RETURN f;
END;
So, I don't need to use CASE inside my plpgsql function if possible :) Tried everything, but it does not work, cast expects constant. Thanks:)
Using Dynamic query:
CREATE OR REPLACE FUNCTION public.somefunction(something numeric)
RETURNS numeric
LANGUAGE plpgsql
AS $function$
DECLARE
f numeric;
x integer;
BEGIN
x := 2;
EXECUTE 'SELECT CAST($1 AS numeric(12, ' || x ||'))' INTO f USING something;
RETURN f;
END;
$function$
;
select somefunction(126.787);
somefunction
--------------
126.79
Alternate where you pass in the scale:
CREATE OR REPLACE FUNCTION public.somefunction(something numeric, scale integer)
RETURNS numeric
LANGUAGE plpgsql
AS $function$
DECLARE
f numeric;
BEGIN
EXECUTE 'SELECT CAST($1 AS numeric(12, ' || scale ||'))' INTO f USING something;
RETURN f;
END;
$function$
;
select somefunction(126.787,2);
somefunction
--------------
126.79
(1 row)
select somefunction(126.787,1);
somefunction
--------------
126.8

Postgresql function loop through input arguments and append to hstore

I'm wondering if it is possibile in PostgreSQL to loop through all available input parameters of the current function and append these arguments (key=>value) to a hstore variabele.
hstore-key = the name of the given input argument/parameter....
hstore-Value = the value of the given argument...
For example:
-- input for call function with input arguments
SELECT append_hstore_from_args ('val1','val22','val333');
CREATE OR REPLACE FUNCTION append_hstore_from_args (IN param1 text, IN param2 text, IN param3 text)
RETURNS text AS
$BODY$
DECLARE
new_h hstore;
BEGIN
-- below is pseudo
for p in all_params
loop
new_h := new_h+"$p->name"=>"$p->value";
end loop;
-- at this point the variable new_h (hstore) should contain
-- '"param1"=>"val1","param2"=>"val22","param3"=>"val333"'
-- call function with hstore argument
perform test.func123(new_h);
RETURN;
END;
$BODY$
LANGUAGE plpgsql VOLATILE SECURITY DEFINER
I've searched, but unfortunately didn't find any hints on how to get this done in PostgreSQL.
I assume that it is a question of how to handle a variable number of function arguments.
Variadic arguments are accessible inside a function as an array. You can use FOREACH ... LOOP:
create or replace function strings_to_hstore(args variadic text[])
returns hstore language plpgsql as $$
declare
idx int = 0;
str text;
hst hstore;
res hstore = '';
begin
foreach str in array args loop
idx:= idx+ 1;
execute format($f$select 'param%s=>%s'$f$, idx, str) into hst;
res:= res|| hst;
end loop;
return res;
end $$;
select strings_to_hstore('one', 'two');
strings_to_hstore
----------------------------------
"param1"=>"one", "param2"=>"two"
(1 row)
select strings_to_hstore('red', 'green', 'blue');
strings_to_hstore
------------------------------------------------------
"param1"=>"red", "param2"=>"green", "param3"=>"blue"
(1 row)
If you wanted to define hstore keys in the argument list:
create or replace function strings_with_keys_to_hstore(args variadic text[])
returns hstore language plpgsql as $$
declare
idx int = 0;
key text;
str text;
hst hstore;
res hstore = '';
begin
foreach str in array args loop
idx:= idx+ 1;
if idx & 1 then
key:= str;
else
execute format($f$select '%s=>%s'$f$, key, str) into hst;
res:= res|| hst;
end if;
end loop;
return res;
end $$;
select strings_with_keys_to_hstore('key1', 'val1', 'key2', 'val2');
strings_with_keys_to_hstore
--------------------------------
"key1"=>"val1", "key2"=>"val2"
(1 row)
Note, that there are standard hstore functions: hstore(text[]) and hstore(text[], text[]).

How postgresql return a data set like the follows?

Just like the below function. I don't know how to return a set of inside parameter in postgresql?
create or replace function g_i(num int)
returns setof integer
as $$
declare
i int;
begin
while i < $1 loop
select i; -- How to write statements here?
end loop;
end;
$$ language plpgsql;
create or replace function g_i(num int)
returns setof integer
as $$
declare
i int;
begin
i := 0;
while i< $1 loop
i := i+1;
return query select i;
end loop;
end;
$$ language plpgsql;

translate plpgsql recursive function back to pg8.1

I have the following plpgsql function that does work great on pg 8.3 and above but I need to translate it back to a pg 8.1 database and I can't seam to get it right.
Any tips? I need to get rid of the "RETURN QUERY" as it was not yet introduced in 8.1...
CREATE OR REPLACE FUNCTION specie_children (specie_id INT, self BOOLEAN)
RETURNS SETOF specie AS
$BODY$
DECLARE
r specie%ROWTYPE;
BEGIN
IF self THEN
RETURN QUERY SELECT * FROM specie WHERE specieid = specie_id;
END IF;
FOR r IN SELECT * FROM specie WHERE parent = specie_id
LOOP
RETURN NEXT r;
RETURN QUERY SELECT * FROM specie_children(r.specieid, FALSE);
END LOOP;
RETURN;
END
$BODY$
LANGUAGE 'plpgsql';
How do I translate this ?
RETURN QUERY SELECT * FROM specie_children(r.specieid, FALSE);
could be rewritten as
for r2 in select * from specie_children(r.specieid, FALSE)
loop
return next r2
end loop
Quick demo. Basically #maniek already provided the answer.
Test table:
CREATE TEMP TABLE specie(specieid int, parent int);
INSERT INTO specie VALUES
(1,0), (2,0), (3,0)
,(11,1), (12,1), (13,1)
,(111,11), (112,11), (113,11);
Rewritten function:
CREATE OR REPLACE FUNCTION specie_children (specie_id INT, self BOOLEAN)
RETURNS SETOF specie AS
$BODY$
DECLARE
r specie%ROWTYPE;
BEGIN
IF self THEN
FOR r IN SELECT * FROM specie WHERE specieid = $1
LOOP
RETURN NEXT r;
END LOOP;
END IF;
FOR r IN SELECT * FROM specie WHERE parent = $1
LOOP
RETURN NEXT r;
FOR r IN SELECT * FROM specie_children(r.specieid, FALSE)
LOOP
RETURN NEXT r;
END LOOP;
END LOOP;
RETURN;
END;
$BODY$
LANGUAGE plpgsql;
Call:
SELECT * FROM specie_children (1, true);
Returns:
specieid | parent
---------+-------
1 | 0
11 | 1
111 | 11
112 | 11
113 | 11
12 | 1
13 | 1

Is there any hash function in PostgreSQL?

I am using Sphinx to index my database.
The problem is I have to filter the result by a character varying field.
So I have to find a way to convert character varying to sql_attr_uint.
I know that CRC32 in mysql can do the trick. Is there a CRC32 or any replacement in PostgreSQL?
This is the CRC32 function that defines thinking sphinx (gem):
CREATE OR REPLACE FUNCTION crc32(word text)
RETURNS bigint AS $$
DECLARE tmp bigint;
DECLARE i int;
DECLARE j int;
DECLARE byte_length int;
DECLARE word_array bytea;
BEGIN
IF COALESCE(word, '') = '' THEN
return 0;
END IF;
i = 0;
tmp = 4294967295;
byte_length = bit_length(word) / 8;
word_array = decode(replace(word, E'\\\\', E'\\\\\\\\'), 'escape');
LOOP
tmp = (tmp # get_byte(word_array, i))::bigint;
i = i + 1;
j = 0;
LOOP
tmp = ((tmp >> 1) # (3988292384 * (tmp & 1)))::bigint;
j = j + 1;
IF j >= 8 THEN
EXIT;
END IF;
END LOOP;
IF i >= byte_length THEN
EXIT;
END IF;
END LOOP;
return (tmp # 4294967295);
END
$$ IMMUTABLE LANGUAGE plpgsql;
Maybe you can use decode(substring(md5('foo') for 8), 'hex'). This would get you bytea of first 4 bytes of md5 hash of this string.
You can convert it to integer using something like:
create function bytea_to_integer(bytea)
returns integer strict
language sql as $$
select
(get_byte($1,0)*1::integer<<0*8)
+(get_byte($1,1)*1::integer<<1*8)
+(get_byte($1,2)*1::integer<<2*8)
+(get_byte($1,3)*1::integer<<3*8);
$$;