I've prepared two execute statements in PostgreSQL which are both update statements. I'd like to run two of them as an iterative loop e.g.
LOOP
EXECUTE stage1
EXECUTE stage2
IF a = b then EXIT;
END IF
END LOOP
But PostgreSQL doesn't like the syntax. Both prepared statements work fine when run on their own, but they take a bit of time and I need to iterate them many times, so I can't really do this manually. Is there some other way of approaching this?
Simple sql language does not support such constructs. If you whant to write in PLPGSQL syntax you have to write a function to do that:
CREATE FUNCTION some_function() RETURNS void AS $$
--your variable declarations here
BEGIN
--your code here
END;
$$ LANGUAGE plpgsql;
you can replace RETURNS void with a type you want to return;
read the documentation here
Related
CREATE OR REPLACE FUNCTION my_function2()
RETURNS VOID
LANGUAGE plpgsql AS
$func$
BEGIN
PREPARE "my-statement7" (text, text) AS
INSERT INTO "table" (key, a_id)
VALUES ($1, $2);
EXECUTE format('EXECUTE "my-statement7" (%1, %2)', 'value1', 'value2');
END;
$func$;
SELECT my_function2();
However this will return error.
I have run successfully when I do execute prepare statement in the command line but when I do it in a function it will prompt error. Somebody said the execute statement will be ambiguous in execute statement or function, so it need put execute into execute format. However, it doesn't work too.
I want to execute the prepare statement for insert because I got a lot of data got to insert in same format, but the data may need to insert to different table (also data are different), so I cannot just do insert multi or COPY for it. I think the prepare statement is the solution for me, but it cannot work in a function. This will bother me if I want to do a lot of "execute prepare statement" in a function.
In PL/SQL, queries are already prepared and cached, so you don't have to.
As each expression and SQL command is first executed in the function, the PL/pgSQL interpreter parses and analyzes the command to create a prepared statement, using the SPI manager's SPI_prepare function. Subsequent visits to that expression or command reuse the prepared statement.
Here's how you'd write it if you tried. Note the use of _ instead of - in the name to avoid quoting issues; no need to format.
CREATE OR REPLACE FUNCTION my_function2()
RETURNS VOID
LANGUAGE plpgsql AS
$func$
BEGIN
PREPARE my_statement7 (text, text) AS
INSERT INTO example (key, a_id)
VALUES ($1, $2);
EXECUTE my_statement7( 'value1', 'value2');
END;
$func$;
However, the first time it will fail (for reasons I don't entirely understand): ERROR: function my_statement7(unknown, unknown) does not exist. The second time it is called it will also fail: ERROR: prepared statement "my_statement7" already exists.
I want to measure the performance of postgresql code I wrote. In the code tables get created, selfwritten functions get called etc.
Looking around, I found EXPLAIN ANALYSE is the way to go.
However, as far as I understand it, the code only gets executed once. For a more realistic analysis I want to execute the code many many times and have the results of each iteration written somewhere, ideally in a table (for statistics later).
Is there a way to do this with a native postgresql function? If there is no native postgresql function, would I accomplish this with a simple loop? Further, how would I write out the information of every EXPLAIN ANALYZE iteration?
One way to do this is to write a function that runs an explain and then spool the output of that into a file (or insert that into a table).
E.g.:
create or replace function show_plan(to_explain text)
returns table (line_nr integer, line text)
as
$$
declare
l_plan_line record;
l_line integer;
begin
l_line := 1;
for l_plan_line in execute 'explain (analyze, verbose)'||to_explain loop
return query select l_line, l_plan_line."QUERY PLAN";
l_line := l_line + 1;
end loop;
end;
$$
language plpgsql;
Then you can use generate_series() to run a statement multiple times:
select g.i as run_nr, e.*
from show_plan('select * from foo') e
cross join generate_series(1,10) as g(i)
order by g.i, e.line_nr;
This will run the function 10 times with the passed SQL statement. The result can either be spooled to a file (how you do that depends on the SQL client you are using) or inserted into a table.
For an automatic analysis it's probably easer to use a more "parseable" explain format, e.g. XML or JSON. This is also easier to handle in the output as the plan is a single XML (or JSON) value instead of multiple text lines:
create or replace function show_plan_xml(to_explain text)
returns xml
as
$$
begin
return execut 'explain (analyze, verbose, format xml)'||to_explain;
end;
$$
language plpgsql;
Then use:
select g.i as run_nr, show_plan_xml('select * from foo')
from join generate_series(1,10) as g(i)
order by g.i;
I would like to create a function in PL/pgSQL with a couple of nested (or inner) functions within it. This way I can break the problem down into smaller pieces but not have my smaller pieces accessible outside of this function.
Is it possible to do this in PL/pgSQL? If so, how?
Try it:
CREATE OR REPLACE FUNCTION outer() RETURNS void AS $outer$
DECLARE s text;
BEGIN
CREATE OR REPLACE FUNCTION inner() RETURNS text AS $inner$
BEGIN
RETURN 'inner';
END;
$inner$ language plpgsql;
SELECT inner() INTO s;
RAISE NOTICE '%', s;
DROP FUNCTION inner();
END;
$outer$ language plpgsql;
In postgres 9.5 SELECT outer(); outputs
psql:/vagrant/f.sql:14: NOTICE: inner
EDIT: if you don't drop the inner
function at the end of the outer function it will remain visible to the rest of the database.
Nested functions are not supported by PLpgSQL. The emulation has not any sense and it is nonproductive.
This is a small thing, but it's a bit annoying to me and seems like there is probably a way to configure it. Let's say I have the following:
CREATE OR REPLACE FUNCTION baz()
RETURNS void AS
$BODY$
DECLARE
BEGIN
RAISE NOTICE 'I also did some work!';
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
CREATE OR REPLACE FUNCTION bar()
RETURNS void AS
$BODY$
DECLARE
BEGIN
RAISE NOTICE 'I did a bunch of work and want you to know about it';
PERFORM baz();
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
CREATE OR REPLACE FUNCTION foo()
RETURNS void AS
$BODY$
DECLARE
BEGIN
PERFORM bar();
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
select foo();
I get the following output messages:
NOTICE: I did a bunch of work and want you to know about it
CONTEXT: SQL statement "SELECT bar()"
PL/pgSQL function "foo" line 4 at PERFORM
NOTICE: I also did some work!
CONTEXT: SQL statement "SELECT baz()"
PL/pgSQL function "bar" line 5 at PERFORM
SQL statement "SELECT bar()"
PL/pgSQL function "foo" line 4 at PERFORM
Total query runtime: 31 ms.
1 row retrieved.
What I want (usually) is to just see something like:
NOTICE: I did a bunch of work and want you to know about it
NOTICE: I also did some work!
Total query runtime: 31 ms.
1 row retrieved.
Is there a way to control/alter this? Again, it's a small thing and hardly worth a question on Stackoverflow, but if you have a lot of stuff going on it starts to introduce a lot of "noise" into the output and it makes my already overloaded brain hurt trying to sift through it. :)
I'm using PostgreSQL 9.1.5 with pgAdminIII 1.16.0
Try connecting with -q option. The q stands for Quiet and may be what you need.
psql -q -d foo_db
you may also try:
\set verbosity terse
\set quiet on
If you want more control over messaging and interface, it might be worth moving to a real scripting language. Writing database scripts in tools like Python with psycopg2 or Perl with DBD::Pg and DBI is pretty simple.
Not only does using a real scripting language give you total control over messaging, but it also gives you control over error handling, gives you loops and other control structures, and generally offers a much nicer model than raw SQL for scripting tasks.
With SQL Server, I can execute code ad hoc T-SQL code with full procedural logic through SQL Server Management Studio, or any other client. I've begun working with PostgreSQL and have run into a bit of a difference in that PGSQL requires any logic to be embedded in a function.
Is there a way to execute PL/PGSQL code without creating an executing a function?
Postgres 9
DO $$
-- declare
BEGIN
/* pl/pgsql here */
END $$;
No, not yet. Version 9.0 (still alpha) will have this option (do), you a have to wait until it's released.
I struggled to get this working because it's fairly strict about adding semi colons in exactly the right places. But once you get used to that it works well. Besides the inability to return records of course, however you can raise notices & exceptions and do the other workarounds like using temp tables as #ErwinBrandstetter pointed out in a comment above.
e.g.:
DO
$$
BEGIN
IF EXISTS(SELECT 'any rows?'
FROM {your_table}
WHERE {your_column} = 'blah')
THEN
RAISE NOTICE 'record exists';
ELSE
RAISE EXCEPTION 'record does not exist';
END IF;
DROP TABLE IF EXISTS foo;
CREATE TEMP TABLE foo AS
SELECT 'bar'::character varying(5) as baz;
END
$$;
SELECT * FROM foo;