How to "PERFORM" a CTE query returning multiple rows/columns? - postgresql

As a follow-up to this question:
How to "PERFORM" CTE queries in PL/pgSQL?
I try:
perform (with test_as_cte as(select * from myTable) select * from test_as_cte);
But get the following error:
SQL Error [42601]: ERROR: subquery must return only one column
Where: PL/pgSQL function inline_code_block line 9 at PERFORM
If I replace * with myCol in the above code there is no error.
However, I need to do realistic performance testing with the CTE and return multiple columns.

The WITH query enclosed in parentheses is treated like a sub-select. It works fine the way you have it as long as it returns a single value (one column of one row). Else you must treat it as subquery and call it like this (inside a PL/pgSQL code block!):
PERFORM * FROM (with test_as_cte as (select * from b2) select * from test_as_cte t) sub;
Or just:
PERFORM FROM (<any SELECT query>) sub;
The manual:
PERFORM query;
This executes query and discards the result. Write the query
the same way you would write an SQL SELECT command, but replace the
initial keyword SELECT with PERFORM. For WITH queries, use
PERFORM and then place the query in parentheses. (In this case, the
query can only return one row.)
I think this could be clearer. I'll suggest a fix for the documentation.

Related

How to execute string query

It is known that you can do EXECUTE SELECT * FROM table1. But how can I execute string queries assuming that the string is valid query for example: EXECUTE 'SELECT * FROM table1;'
EXECUTE is a PL/pgSQL command and cannot be used in plain SQL queries.
You'll have to write a PL/pgSQL function to use EXECUTE, but the simplest way to do what you seem to want to do is to use RETURN QUERY EXECUTE to return the query results from the function.
You can define the function with RETURNS SETOF RECORD to avoid having to specify the result columns at function definition time, but then you need to specify them when you call the function.

How to select a table from a function param

I have the function:
test(IN _partition)
Inside my function I would like to append the '_partition' to the beginning of my table name.
FROM table_ + '_partition'
The end result:
select * from test(12345);
This function will query the table: table_12345
You need PL/PgSQL dynamic SQL with EXECUTE and the format function, e.g.
RETURN QUERY EXECUTE format('SELECT * FROM %I', _partition);
However, this is a mark of a design that will probably be painful to work with.
Have you looked at PostgreSQL's table inheritance features?

dynamic sql query in postgres

I was attempting to use Dynamic SQL to run some queries in postgres.
Example:
EXECUTE format('SELECT * from result_%s_table', quote_ident((select id from ids where condition = some_condition)))
I have to query a table, which is of the form result_%s_table wherein, I need to substitute the correct table name (an id) from an another table.
I get the error ERROR: prepared statement "format" does not exist
Link: string substitution with query result postgresql
EXECUTE ... USING only works in PL/PgSQL - ie within functions or DO blocks written in the PL/PgSQL language. It does not work in plain SQL; the EXECUTE in plain SQL is completely different, for executing prepared statements. You cannot use dynamic SQL directly in PostgreSQL's SQL dialect.
Compare:
PL/PgSQL's EXECUTE ... USING; to
SQL's EXECUTE
See the 2nd last par in my prior answer.
In addition to not running except in PL/PgSQL your SQL statement is wrong, it won't do what you expect. If (select id from ids where condition = some_condition) returns say 42, the statement would fail if id is an integer. If it's cast to text you'd get:
EXECUTE format('SELECT * from result_%s_table', quote_ident('42'));
EXECUTE format('SELECT * from result_%s_table', '"42"');
EXECUTE 'SELECT * from result_"42"_table';
That's invalid. You actually want result_42_table or "result_42_table". You'd have to write something more like:
EXECUTE format('SELECT * from %s', quote_ident('result_'||(select id from ids where condition = some_condition)||'_table'))
... if you must use quote_ident.
CREATE OR REPLACE FUNCTION public.exec(
text)
RETURNS SETOF RECORD
LANGUAGE 'plpgsql'
AS $BODY$
BEGIN
RETURN QUERY EXECUTE $1 ;
END
$BODY$;
usage:
select * from exec('select now()') as t(dt timestamptz)
Try using
RETURN QUERY EXECUTE '<SQL Command>'
This will return data into form of table. You have to use this into stored function of PostgreSQL.
I have already created on full demonstration on custom filter and custom sorting using dynamic query of PostgreSQL.
Please visit this url:
http://www.dbrnd.com/2015/05/postgresql-dynamic-sql/
These all look more complicated than the OP's question. A different formatting should do the trick.. but it could absolutely the case that I don't understand.
From how I read OP's question, I think others in a similar situation may benefit from how I got it.
I am using Postgre on Redshift, and I ran into this issue and found a solution.
I was trying to create a dynamic query, putting in my own date.
date = dt.date(2018, 10, 30)
query = ''' select * from table where date >= ''' + str(my_date) + ''' order by date '''
But, the query entirely ignores the condition when typing it this way.
However, if you use the percent sign (%), you can insert the date correctly.
One correct way to write the above statement is:
query = ''' select * from table where date >= ''' + ''' '%s' ''' % my_date + ''' order by date '''
So, maybe this is helpful, or maybe it is not. I hope it helps at least one person in my situation!
Best wishes.
EXECUTE will work only on pl/pqsql environment.
instead of EXECUTE try with SELECT
SELECT format('SELECT * from result_%s_table', quote_ident((select id from ids where condition = some_condition))
output would be the dynamic query.

Avoiding execution of some PL/PGSQL functions by query rewriting

I would like to allow the execution of a PL/PGSQL function (my_function) only if its argument (my_table.x) belongs to a predefined interval (e.g. [100,1000]).
Let's take the following query example :
(q) SELECT * FROM my_table WHERE my_function(mytable.x);
I would like this query automatically rewrites itself to check whether mytable.x belongs to the interval [100,1000] :
(q') SELECT * FROM my_table WHERE (my_table.x BETWEEN 100 AND 1000) AND my_function(my_table.x);
The command EXPLAIN ANALYSE shows that the second query is really faster than the first one.
How can I change the query execution plan in order to automate the process of query rewriting (q into q') ?
Where can I store suitably the metadata about the interval [100,1000] associated to my_function ?
Thanks by advance,
Thomas Girault
The help I need will help a project about the integration of fuzzy logics into PostgreSQL : [https://github.com/postgresqlf/PostgreSQL_f/][PostgreSQLf]
The fastest way to catch it is something like this at the top of the function body:
IF $1 BETWEEN 100 AND 1000 THEN
-- proceed
ELSE
RETURN NULL; -- Or what ever you want to return in this case
END IF;
This should be very fast.
Actual query rewriting is done with the RULE system in PostgreSQL. But rules apply to tables and views, not to functions. You could wrap your query in a view - but then you can add the additional condition explicitly, which is cheaper.
CREATE VIEW v_tbl_only_valid_x AS
SELECT *
FROM tbl
WHERE x BETWEEN 100 AND 1000;
Call:
SELECT * FROM v_tbl_only_valid_x WHERE my_function(x);
This way the query planner gets the information about the selectivity of the query on the column x explicitly, which may result in a different query plan.
But wouldn't it be simpler to just add the second WHERE condition in your query like you have it in q'?

TSQL How to exec a stored procedure inside select query?

is it possible to execute a storep procedure inside select query ?
select e.Name, dbo.get_sth e.Id
from emp e
I get the error
Incorrect syntax near 'e.Id'
No. But you can execute a function inside a select statement. So recreate your Stored Procedure as a function and this should work.
It will be called for every row so be careful of performance if returning many rows.