Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I have function in pl/pgsql in postgresql
ie
CREATE or replace FUNCTION check_checklist_is_finalizedtest(application_id bigint)
RETURNS SETOF record AS
$BODY$
DECLARE
sqlresult record;
val boolean:=false;
BEGIN
for sqlresult in execute IMMEDIATE 'select distinct mda.application_id maid,mda.document_type_id mdoctypeid,
dt.multiple_doc dtmdoc,mda.mandatory_doc_application_id mdocaid,COALESCE(ac.doc_correct,false) doccorrect,
COALESCE((select max(e_certificate_no) from application_document ad
where ad.application_id=mda.application_id and ad.document_id=mda.document_type_id and multiple_doc=true and ad."valid"=''||New||''
),'''||1||''')as no_of_docs,
(select count(*) from application_document ad2
where ad2.application_id=mda.application_id and ad2.document_id=mda.document_type_id and ad2."valid"=''||New||''
)as count_of_record
from mandatory_doc_application mda
inner join document_type dt on(mda.document_type_id=dt.document_id)
left join application_checklist ac on(ac.man_doc_app_id= mda.mandatory_doc_application_id)
where mda.application_id='''||$1||''''
LOOP
IF(sqlresult.no_of_docs::bigint=sqlresult.count_of_record and sqlresult.doccorrect=true) then
val=true;
ELSE
val=false;
END IF;
return next sqlresult;
END LOOP;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
When function is called subqueries in select statement are not executed.Hence the result is wrong.Can you help me?
Probably something went wrong translating your query to dynamic SQL. The code in your question is very hard to read, which increases the risk of errors.
This strange expression probably does not what you think it does:
and ad2."valid"=''||New||''
You expect a variable New, but it is not declared and you use a constant string there instead.
Next strange thing: the key word IMMEDIATE - PostgreSQL doesn't support it - so your code cannot be compiled probably.
Questions:
Why do you use a dynamic SQL? There doesn't seem to be need for that.
If you use a dynamic SQL, why you don't use a modern form like
FOR r IN EXECUTE 'SELECT * FROM tab WHERE somecol = $1' USING $1
LOOP ...
But your code would be simpler and faster with plain SQL:
BEGIN
RETURN QUERY SELECT no_of_docs::bigint=count_of_record
AND COALESCE(ac.doc_correct,false) = true
FROM ...;
RETURN;
END;
Remember to only select columns that you actually need to return - not others.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I have one table called empl, and have another table new_empl with the same columns and definition with empl. Is it possible to insert records from v_record in new_empl using the following code ?
DECLARE
v_record empl%rowtype;
BEGIN
Insert into new_empl values v_record;
END;
There are too many columns in empl table and I want to avoid listing them.
The above snippet would work for Oracle, but for Postgres/pgplsql, the following snippet works like a charm:
DECLARE
v_record empl%rowtype;
BEGIN
Insert into new_empl values (v_record.*);
END;
Is it possible to insert records from v_record in new_empl using the
following code
Yes its possible however the way you are doing insert will not insert anything as nothing to assigned to the variable v_record . Rather you can do something like below:
DECLARE
v_record empl%rowtype;
BEGIN
Insert into new_empl Select * from empl;
END;
But why you want to do it in a PLSQL block when you can do it SQL itself.
Insert into new_empl select * from empl;
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
Disclaimer This might be a more theoretical, unpractical question.
I am trying to replace a plpgsql function by a sql function without changing the behaviour or result type. The function looks like this:
create function f() returns void as
$$
begin
perform some_other_function(my_table.my_column)
from my_table;
end;
$$
language plpgsql volatile;
This function returns void, as I do not care about the results.
As said, I am trying to replace it by a sql function. This function is used in a chain of sql functions, so it might be performance-wise better to have this function also a sql function instead of plpgsql (again, see disclaimer).
The following does not work, because now only the first row of my_table is processed.
create function f() returns void as
$$
select some_other_function(my_table.my_column)
from my_table;
$$
language sql volatile;
Note that function some_other_function also returns a void.
Any other clever ways to try out?
You could use an SQL statement that has to scan the whole table before it can produce the first result row, like
CREATE OR REPLACE FUNCTION f() RETURNS void
LANGUAGE sql STABLE AS
'SELECT count(CASE
WHEN some_other_function(my_table.my_column) IS NULL
THEN 0
END
)::text::void
FROM my_table';
or
CREATE OR REPLACE FUNCTION f() RETURNS void
LANGUAGE sql STABLE AS
'SELECT count(*)::text::void
FROM (
SELECT some_other_function(my_table.my_column)
FROM my_table
) q';
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I am trying to calculate the age of a person when a record is inserted or updated in table staff but somehow the below trigger function does not work:
create or replace function Age()
returns trigger as $body$
declare
dob1 date;
age1 integer;
BEGIN
select dob into dob1 from staff;
select age(current_date,dob) into age1;
update staff set age=age1;
END; $body$ language plpgsql;
create trigger trig_age
before insert or update on staff
FOR EACH ROW
execute procedure age();
I'm not sure about this above code. I want a trigger to calculate and insert the AGE when inserting DOB in some table
First of all, the name of the trigger function may not be the most appropriate. There is already an overloaded regular function by that name and while the parameters differ and PostgreSQL will therefore accept it, you might confuse whomever has to work with your code.
Otherwise you are not far off. The principal change is that you should not call an UPDATE in a trigger function for the same table that the trigger is fired for: you may get an infinite loop. Just use assignments to the NEW implicit parameter. Since you obviously want the age in years of a person, you should get that specific date_part() into field age.
CREATE OR REPLACE FUNCTION age_in_years() RETURNS TRIGGER AS $body$
BEGIN
NEW.age := date_part('year', CURRENT_TIME - NEW.dob::timestamp);
RETURN NEW; -- or the insert or update would fail
END;
$body$ LANGUAGE plpgsql;
Setting the values in the NEW parameter and returning that parameter at the end of the function will change the values that will be inserted or updated into the table.
However, a person's age may change in between updates so you are probably better off dropping the column age from table staff (and thus also the trigger) and then creating a view that calculates the age whenever that view is accessed:
CREATE VIEW staff_today AS
SELECT *, date_part('year', CURRENT_TIME - dob::timestamp) AS age
FROM staff;
Like so you will always get the correct age.
This question already has answers here:
Committing transactions while executing a postgreql Function
(4 answers)
Closed 8 years ago.
I have written a function for automation, mentioned below, which calls some other functions based on some rules. The function is giving me the desired results, but the problem that I am facing is that it does not commit the data after each of the function is processed internally. Once the main function gets completed only then it commits the entire data. I want to do a internal transaction which should commit the data as and when the internal function execution get completed. I tried giving a COMMIT statement after each of the PERFORM statements, but I got an error saying 'cannot begin/end transactions in PL/pgSQL'.
Can anyone suggest how do I go about doing a transaction inside a function.
CREATE OR REPLACE FUNCTION ccdb.fn_automation_for_updation()
RETURNS void AS
$BODY$
DECLARE
sec_col refcursor;
cnt integer;
sec_code ccdb.update_qtable%ROWTYPE;
new_cnt integer;
BEGIN
SELECT COUNT(*)
INTO cnt
FROM ccdb.update_qtable
WHERE status_flag IN (-1,1);
OPEN sec_col FOR
SELECT * FROM ccdb.update_qtable WHERE status_flag IN (-1,1);
FOR i IN 1..cnt
LOOP
FETCH sec_col INTO sec_code;
PERFORM ccdb.o_dtr_update(sec_code.section_code);
PERFORM ccdb.o_consumer_update_for_update(sec_code.section_code);
PERFORM ccdb.o_consumer_update_for_insert(sec_code.section_code);
PERFORM ccdb.o_bills_update_for_update(sec_code.section_code);
PERFORM ccdb.o_bills_update_for_insert(sec_code.section_code);
PERFORM ccdb.o_payments_update_for_update_new(sec_code.section_code);
PERFORM ccdb.o_payments_update_for_insert(sec_code.section_code);
PERFORM ccdb.o_payments_map_update_for_update(sec_code.section_code);
PERFORM ccdb.o_payments_map_update_for_insert(sec_code.section_code);
SELECT COUNT(*) INTO new_cnt FROM ccdb.update_qtable WHERE status_flag IN (-1,1);
IF new_cnt > cnt
THEN
CLOSE sec_col;
OPEN sec_col FOR
SELECT * FROM ccdb.update_table WHERE status_flag IN (-1,1);
cnt := new_cnt;
END IF;
END LOOP;
CLOSE sec_col;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
You cannot perform autonomous transactions in PostgreSQL - its functions don't support it.
You must use DBLink.
See:
Committing Records into the table while executing a postgreql Function
Are PostgreSQL functions transactional?
COMMIT in PostgreSQL stored procedure
(Marked CW because I closed the post)
This question already has answers here:
Error: query has no destination for result data while using a cursor
(2 answers)
Function with SQL query has no destination for result data
(3 answers)
Closed 8 years ago.
i have table like below with name student
S.No Name
1. Ramesh
2. Raju
3. SOmu
-------------
------------- etc
My requirement is when i am passing the S.no i will get the Name by using function
My function like below:
CREATE OR REPLACE FUNCTION fn_name(v_sno bigint)
RETURNS TEXT
AS
$BODY$
DECLARE RESULT VARCHAR(5000);
BEGIN
SELECT RESULT "Name" FROM "Student" WHERE "s.no" = v_sno;
RETURN RESULT;
END;
$BODY$
LANGUAGE plpgsql
COST 100;
ALTER FUNCTION fn_name(bigint)
OWNER TO postgresql
but i am getting the following error .
ERROR: query has no destination for result data
SQL state: 42601
Hint: If you want to discard the results of a SELECT, use PERFORM instead.
Context: PL/pgSQL function fn_name(bigint) line 6 at SQL statement
please help me how to resolve the above issue.
The immediate question is easily answered by the manual (see SELECT INTO).
However, all that is a rather overcomplicated way to do what you want. Things notably wrong:
varchar(5000) is weird and unnecessary. Use text or unqualified varchar.
SELECT RESULT "Name" doesn't do what you probably think it does. That's trying to SELECT a column named result and alias it as Name. I think you were looking for SELECT INTO.
"s.no" means the column named s.no. Is that what you meant? Because that's a horrid name for a column; without the quotes it'd be interpreted as the column no from the table s. Don't use periods in column names or table names.
All you really need is:
CREATE OR REPLACE FUNCTION fn_name(bigint)
RETURNS TEXT AS
$BODY$
SELECT "Name" FROM "Student" WHERE "s.no" = $1;
$BODY$
LANGUAGE sql;
(assuming "s.no" really is your column name, not a mangled attempt at an alias).
If you had to use PL/PgSQL for this simple job for some reason (maybe you intend to make it more complex later), you'd write:
CREATE OR REPLACE FUNCTION fn_name(v_sno bigint)
RETURNS TEXT AS
$BODY$
DECLARE
result text;
BEGIN
SELECT INTO result "Name" FROM "Student" WHERE "s.no" = $1;
RETURN result;
END;
$BODY$
LANGUAGE plpgsql;