CREATE OR REPLACE FUNCTION "public"."sxfun"("jcbh" text)
RETURNS "pg_catalog"."int4" AS $BODY$
declare leftplayer TEXT;
declare rightplayer TEXT;
declare leftcoin int;
BEGIN
SELECT player1 into leftplayer,player2 into rightplayer FROM table1 WHERE id=$1;
SELECT SUM(playcoin) into leftcoin FROM table2 WHERE playname=leftplayer
COMMIT;
END$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
this code syntax error,let how to solve it,please
You are missing a return statement. In PL/pgSQL, declare starts a block, there is no need to repeat the keyword for every variable. And you can't commit in a function - and you don't need it to begin with.
As documented in the manual you need to use return to return a value from a function.
To store multiple columns into multiple variables, you need to separate them with a comma, not repeat the INTO clause.
Note that sum() returns a bigint, so your variable and return type should also be defined as bigint.
CREATE OR REPLACE FUNCTION public.sxfun(jcbh text)
RETURNS bigint
AS
$BODY$
declare
leftplayer TEXT;
rightplayer TEXT;
leftcoin bigint;
BEGIN
SELECT player1, player2
into leftplayer, rightplayer
FROM table1
WHERE id = jcbh;
SELECT SUM(playcoin)
into leftcoin
FROM table2
WHERE playname = leftplayer;
return leftcoin; --<< return the value
END
$BODY$
LANGUAGE plpgsql;
If id is a number (which the name usually indicates), the parameter jcbh should be declared as integer, not as text.
Note that you can simplify this to a single statement. There is no need for intermediate variables:
CREATE OR REPLACE FUNCTION public.sxfun(jcbh text)
RETURNS bigint
AS
$BODY$
SELECT SUM(playcoin)
FROM table2
WHERE playname IN (select leftplayer
FROM table1
WHERE id = jcbh);
$BODY$
LANGUAGE sql;
Related
Suppose I have the following table, function and execution:
create table mytable (a INTEGER, b INTEGER);
create function test(q INTEGER)
returns table(a INTEGER, b INTEGER)
as
$body$
begin
return query select a,b from mytable;
end;
$body$
language plpgsql STABLE;
select * from test(1);
I get an 'ambiguous column name' error. I can get rid of it by changing the selection to "select t.a, t.b from mytable t" (per some similar-ish posts). But it seems very odd to have to qualify the column names when there is only 1 table in my query. I'm porting code that has quite a lot of stored procedures selecting from single tables (in various ways) and returning a table with columns that have the same name. Is there a better way than this of avoiding the error, and still having an output table with the same column names?
Thanks for any leads.
you can (you should) to use aliases.
create table mytable (a INTEGER, b INTEGER);
create function test(q INTEGER)
returns table(a INTEGER, b INTEGER)
as
$body$
begin
return query select mt.a, mt.b from mytable mt;
end;
$body$
language plpgsql STABLE;
select * from test(1);
maybe thats an option, using format and query execute:
( as the error says, it doesnt know which a to take, the pl/pgSQL variable or a columname )
create function test(q INTEGER)
returns table(a INTEGER, b INTEGER)
as
$body$
declare
lsQueryExecute text;
begin
lsQueryExecute = format('select a,b from mytable');
return query execute lsQueryExecute;
end;
$body$
language plpgsql STABLE;
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() ;
Why does accessing a value of the RECORD argument like this works:
CREATE OR REPLACE FUNCTION TT_GetVal1(a RECORD)
RETURNS text AS $$
DECLARE
BEGIN
RETURN a.val1::text;
END;
$$ LANGUAGE plpgsql VOLATILE;
SELECT TT_GetVal1(foo.*)
FROM (SELECT 1 id, 'a' val1) foo;
But not like this:
CREATE OR REPLACE FUNCTION TT_GetVal2(a RECORD)
RETURNS text AS $$
DECLARE
query text;
result text;
BEGIN
query = 'SELECT ($1).val1::text';
EXECUTE query INTO result USING a;
RETURN result;
END;
$$ LANGUAGE plpgsql VOLATILE;
SELECT TT_GetVal2(foo.*)
FROM (SELECT 1 id, 'a' val1) foo;
which returns:
ERROR: could not identify column "val1" in record data type
LINE 1: SELECT ($1).val1::text
How can I dynamically access RECORD values?
The RECORD only lives inside the plpgsql scope. The values are passed to the execute but not the column names.
You can - if the record is from a table - do something like this:
create table table1 (
id integer,
val1 text
);
CREATE OR REPLACE FUNCTION TT_GetVal2(a RECORD)
RETURNS text AS $$
DECLARE
query text;
result text;
BEGIN
query = 'SELECT ($1::text::table1).val1';
EXECUTE query INTO result USING a;
RETURN result;
END;
$$ LANGUAGE plpgsql VOLATILE;
SELECT TT_GetVal2(foo)
FROM (SELECT 1 id, 'a' val1) foo;
Best regards,
Bjarni
I'm trying to get a customer id which can be placed in one of ten different tables. I don't want to hard code those table names to find it so I tried postgresql function as follows.
create or replace FUNCTION test() RETURNS SETOF RECORD AS $$
DECLARE
rec record;
BEGIN
select id from schema.table_0201_0228 limit 1 into rec;
return next rec;
select id from schema.table_0301_0331 limit 1 into rec;
return next rec;
END $$ language plpgsql;
select * from test() as (id int)
As I'm not familiar with postgresql function usage, how can I improve the code to replace 'schema.table1' with a variable, loop each table and return the result?
NOTE: table names may change overtime. For example, table_0201_0228 and table_0301_0331 are for February and March respectively.
You need dynamic SQL for that:
create or replace FUNCTION test(p_schema text)
RETURNS table(id int)
AS $$
DECLARE
l_tab record;
l_sql text;
BEGIN
for l_tab in (select schemaname, tablename
from pg_tables
where schemaname = p_schema)
loop
l_sql := format('select id from %I.%I limit 1', l_tab.schemaname, l_tab.tablename);
return query execute l_sql;
end loop;
END $$
language plpgsql;
I made the schema name a parameter, but of course you can hard-code it. As the function is defined as returns table there is no need to specify the column name when using it:
select *
from test('some_schema');
I tried using setof and table. While creating function in pgAdmin 4.2 there is no return type called setof or table. If I create function with setof and table name as a selected return type, it only returns one row of table.
CREATE FUNCTION pgsql_returnrecords() RETURNS SETOF RECORD(name char, city, char, id integer) AS
$BODY$
DECLARE
rec RECORD;
BEGIN
select name,city,id INTO rec from test;
return next rec;
END;
$BODY$ language plpgsql;
I want my function to return table data with all rows and columns.
It's either returns setof record or returns table(....) or setof table_name With returns setof record you have to specify the column names when using the function.
You are also not returning a complete result, because you only fetch a single row, put it into the record and return that. To return a real "set" you need to use return query in PL/pgSQL. But such a function is much better written as a SQL function:
CREATE FUNCTION pgsql_returnrecords()
RETURNS table(name text, city text, id integer)
AS
$BODY$
select name,city,id
from test;
$BODY$
language sql;
If you want to always return a complete row from the table test you can simplify that using returns setof test instead of returns table(..)
CREATE FUNCTION pgsql_returnrecords()
RETURNS setof test
AS
$BODY$
select *
from test;
$BODY$ language sql;
Or, if you insist on PL/pgSQL:
CREATE FUNCTION pgsql_returnrecords()
RETURNS table(name text, city text, id integer)
AS
$BODY$
BEGIN
return query
select name,city,id
from test;
END;
$BODY$
language plpgsql;
In both cases you have to use the function like a table in the FROM clause:
select *
from pgsql_returnrecords() ;