I need to support postgresql and oracle in the product that I work in. When we install our db on oracle, we do not give privilege of "create type". So I am unsure as to how I can convert following two cases to oracle:
Function That returns array
create or replace function get_array_of_integers(i_param int)
returns integer[] as
$body$
declare array_of_integers int[];
begin
select
case
when i_param = 1 then
array[1]
when i_param = 2 then
array[1, 2, 3, 4]
when i_param = 3 then
array[5, 6]
else
array[]::integer[]
end into array_of_integers;
return array_of_integers;
end;
$body$
language 'plpgsql' volatile
cost 100;
Second case: function that accepts array of integers:
create or replace function some_function(params int[])
...
You could make use of Oracle's built-in collection type sys.odcinumberlist.
Your function is equivalent to.
CREATE OR REPLACE FUNCTION get_array_of_integers(i_param INT)
RETURN sys.odcinumberlist
AS
array_of_integers sys.odcinumberlist := NEW sys.odcinumberlist() ; --Initialization
BEGIN
IF i_param = 1 THEN
array_of_integers.EXTEND(1);
array_of_integers(1) := 1;
ELSIF i_param = 2 THEN
array_of_integers.EXTEND(4);--appends 4 null elements to a collection
array_of_integers(1) := 1; --assign elements
array_of_integers(2) := 2;
array_of_integers(3) := 3;
array_of_integers(4) := 4;
ELSIF i_param = 3 THEN
array_of_integers.EXTEND(2);
array_of_integers(1) := 5;
array_of_integers(2) := 6;
END IF;
RETURN array_of_integers;
END;
/
You may use TABLE function in your query to select from this table.
SQL> select * FROM TABLE(get_array_of_integers(2));
COLUMN_VALUE
------------
1
2
3
4
SQL> select * FROM TABLE(get_array_of_integers(0));
no rows selected
For Oracle 12.2 and above, you won't need TABLE function, you can directly select from your function.
select * FROM get_array_of_integers(3);
Second case could be something like this.
CREATE OR REPLACE FUNCTION some_function( params sys.odcinumberlist )
RETURN INTEGER
AS
BEGIN
RETURN 1;
END;
/
Related
I want to give out result from a PostgreSQL database sequentially like a python Generator.
When the function get_data is called every time I want to return a new 10 rows from the rows.
I defined a sequence called an_iter which is increased by 10:
create sequence an_iter
increment by 10;
My plan is to create a function that
increases the sequence by 10
return the rows which are bigger than
sequence's current value (limit to 10)
My function definition:
CREATE OR REPLACE FUNCTION public.get_data()
RETURNS SETOF ppdb
LANGUAGE plpgsql AS
$func$
declare
val integer := 0;
BEGIN
select nextval('an_iter') into val;
Return Query SELECT * from ppdb where i<= val+10 limit 10;
END
$func$;
Though I called the function the same result set is returned.
Have you tried using BETWEEN? Doing so you can get rid of the LIMIT 10, e.g.
CREATE OR REPLACE FUNCTION public.get_data()
RETURNS SETOF ppdb
LANGUAGE plpgsql AS
$func$
declare
val integer := 0;
BEGIN
SELECT nextval('an_iter') INTO val;
RETURN QUERY SELECT * FROM ppdb
WHERE i BETWEEN val AND val+10;
END
$func$;
Demo: db<>fiddle
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')
This is an example but I want only a column with 1-10 values without other text columns.
CREATE OR REPLACE FUNCTION somefun_recordset(param_numcount integer)
RETURNS SETOF record AS
$$
DECLARE
result text := '';
searchsql text := '';
var_match record;
BEGIN
searchsql := 'SELECT n || '' down'' As countdown, n as integer
FROM generate_series(' || CAST(param_numcount As text) || ', 1, -1) As n ';
FOR var_match IN EXECUTE(searchsql) LOOP
RETURN NEXT var_match;
END LOOP;
END;
$$
LANGUAGE 'plpgsql' IMMUTABLE;
SELECT r.n , r.countdown
FROM somefun_recordset(10)
As r(countdown text, n integer)
ORDER BY r.n;
How do I create a loop in postgres?
From your current description, you seem to be over-complicating this.
As described in the Postgres manual, the generate_series function can generate a column of values from 10 to 1, like so:
SELECT generate_series(10, 1, -1) as n;
Or using it as a table alias rather than a column alias:
SELECT * FROM generate_series(10, 1, -1) as n;
If you wanted to wrap this in a custom function with only one parameter, it would look like this:
CREATE FUNCTION countdown(param_numcount INT) RETURNS SETOF INT LANGUAGE SQL AS $$
SELECT generate_series(param_numcount, 1, -1);
$$;
Then you would run it as:
SELECT countdown(10) as n;
I have problems with this function and couldn't figure out how to fix it.
Create Function Quy(sdate timestamp)
returns integer as $$
declare
numbmonth integer;
quy integer;
Begin
numbmonth := Date_part('month',sdate);
If numbmonth < 4 then
quy := 1;
else if numbmonth < 7 then
quy := 2;
else if numbmonth < 10 then
quy := 3;
else quy := 4;
return quy;
END;
$$
LANGUAGE plpgsql;
This happens when I try to run the code:
ERROR: syntax error at or near ";"
LINE 16: END;
I really don't understand what is wrong with this.
Multiple syntax errors. The function would work like this:
CREATE OR REPLACE FUNCTION quy(sdate timestamp)
RETURNS integer AS
$func$
DECLARE
numbmonth integer := date_part('month', sdate);
quy integer;
BEGIN
IF numbmonth < 4 THEN
quy := 1;
ELSIF numbmonth < 7 THEN
quy := 2;
ELSIF numbmonth < 10 THEN
quy := 3;
ELSE
quy := 4;
END IF;
RETURN quy;
END
$func$ LANGUAGE plpgsql;
Consult the manual for the basic syntax of IF.
But that's much ado about nothing. To get the quarter of the year use the field specifier QUARTER with date_part() or EXTRACT() in a simple expression:
EXTRACT(QUARTER FROM $timestamp)
EXTRACT is the standard SQL equivalent of date_part().
Either returns double precision, so cast to integer if you need that (::int).
If you still need a function:
CREATE OR REPLACE FUNCTION quy(sdate timestamp)
RETURNS int LANGUAGE sql IMMUTABLE AS
'SELECT EXTRACT(QUARTER FROM $1)::int';
$1 is the reference to the 1st function parameter. Equivalent to sdate in the example. $-notation works in any version of Postgres, while named parameter references in SQL functions were only introduced with Postgres 9.2. See:
PLPGSQL Function to Calculate Bearing
dbfiddle here
I have integer array {0,23,1,29,0,15,1} postgres(V 9.3.6) and i want to remove particular element which highlighted above using it's index for example it's 3 as of now i get those element index using function idx
CREATE OR REPLACE FUNCTION idx(anyarray, anyelement)
RETURNS int AS
$$
SELECT i FROM (
SELECT generate_series(array_lower($1,1),array_upper($1,1))
) g(i)
WHERE $1[i] = $2
LIMIT 1;
$$ LANGUAGE sql IMMUTABLE;
But I'm unable to found any built in function in postgres which allows removal by using index.
create or replace function idx(the_array anyarray, idx integer)
returns anyarray as $$
select array_agg(a order by i)
from (
select
generate_series(1, array_upper(the_array, 1)),
unnest(the_array)
) s(i, a)
where i != idx
; $$ language sql;
select idx(array[0,23,1,29,0,15,1], 3);
idx
------------------
{0,23,29,0,15,1}