Alias for a complete SQL statement? (in PostgreSQL psql) - postgresql

In PostgreSQL 9.5 psql (for use within an interactive session), I wold like to create an alias to a complete SQL statement, analogous to a shell alias. The objective is to just get the output printed on the screen.
If I could enable formatted server output (in Oracle terms) from within a stored procedure, it would look like this:
CREATE or replace FUNCTION print_my_table()
RETURNS void
AS $$
-- somehow enable output here
SELECT * from my_table;
$$ LANGUAGE SQL;
This would be invoked as print_my_table(); (as opposed to SELECT x FROM ...)
I know I can use 'RAISE NOTICE' to print from within a stored procedure, but to do that I would need to reimplement pretty-printing of a table.
Perhaps there is a completely different mechanism to do this?
(my_table stands for a complex SQL statement that collects server data accounting information, or a my_table() stored procedure returning a table)
EDIT
The solution provided by #Abelisto (using psql variables) enables the creation of aliases to arbitrary statements, beyond merely printing the result to the screen.

There is so called internal variables in the psql utility which will be replaced by its content (except inside the string constants):
postgres=# \set foo 'select 1;'
postgres=# :foo
?column?
----------
1
(1 row)
It can be also set by the command line option -v:
psql -v foo='select 1;' -v bar='select 2;'
Create the text file like
\set foo 'select 1;'
\set bar 'select 2;'
\set stringinside 'select $$abc$$;'
and load it using \i command.
Finally you can create the file ~/.psqlrc (its purpose is like ~/.bashrc file) and its content will be automatically executed each time when psql starts.

Related

\set command in EDB Postgresql

In EDB Postgres, \set command is used to set variables, like for example \set detpno 80 and while inserting we can use :deptno instaed of actual value like
insert into dept values (:deptno, 'SALES', 'HYD');
it's working fine, but when i use it in Procedure or anonymous block its throwing error.
simple anonymous block
begin
insert into dept values (:deptno, 'SALES', 'LONDON');
end;
when i execute this block, I am getting below error
ERROR: syntax error at or near ":"
LINE 2: insert into dept1 values (:deptno, 'SALES', 'BAN');
Please help me out to use \set variable in procedures or functions.
The substitution of :varname with something that was previously \set is a feature of a particular database client, namely "psql" (although maybe other clients have emulated this behavior). It is not a feature of the database itself. The database doesn't see the :varname, it only sees what it was substituted with.
When you use an anonymous code block, you are by-passing the client's substitution behavior.
Perhaps you should create a function, which declares what parameters it takes in a proper way, rather than using shell-like variable interpolation.
The psql variables cannot be used inside server side code - anonymous blocks. It is just not allowed - the substitution is blocked inside string. You can use a workaround.
set a custom guc variable (custom configuration value). The prefix 'xx' is requested.
postgres=# \set myval AHOJ
postgres=# select set_config('xx.myval', :'myval', false);
┌────────────┐
│ set_config │
╞════════════╡
│ AHOJ │
└────────────┘
(1 row)
Now you can read the value by function current_setting on server side
postgres=# do $$
begin
raise notice '%', current_setting('xx.myval');
end;
$$;
NOTICE: AHOJ
DO
Currently there are not any other way how to do it. This is Postgres - but EDB is very similar in this case.

Is it possible to use dynamic SQL or host variables in DB2 control center?

I need to test some prepared statements that run slowly.
The control center uses JDBC.
In DB2 there's the CREATE VARIABLE statement. I guess it creates a variables on server, not a prepared statement parameter.
I need something like these:
select * from sysibm.sysdummy1 where 1=?;
SQL0313N The number of host variables in the EXECUTE or OPEN statement is not equal to the number of values required.
select * from sysibm.sysdummy1 where 1=:b1;
SQL0312N The host variable "b1" is used in a dynamic SQL statement, a view definition, or a trigger definition.
You can create a bash/batch script and execute it from db2clp
db2 connect to mydb
export b1=value
db2 "select * from sysibm.sysdummy1 where 1=$b1"
The script will replace the content of the variable.

How to save and restore value of ON_ERROR_STOP?

Is there a way to save, temporarily change, and then restore the value of the psql ON_ERROR_STOP variable?
Basically, I'd like to have the "moral equivalent" of the following in a psql script:
save_on_error_stop=ON_ERROR_STOP
\unset ON_ERROR_STOP
ALTER TABLE foo DROP COLUMN bar; -- (for example)
\set ON_ERROR_STOP save_on_error_stop
ALTER TABLE foo ADD COLUMN bar;
The point being that the '\set' command at the end won't actually set ON_ERROR_STOP unless it was set before.
I don't think it is possible to do this in a single psql session. According to the manual, one can use \set command on it's own to list all psql variables.
One can memorize the setting in shell, but this makes the whole thing useless, as it is much more simple just to execute the desired set of queries enforcing the desired ON_ERROR_STOP value.
Another alternative is to write an anonymous code block and DO some extra logic to detect, whether column needs to be dropped before adding it.
BTW, What is the purpose of dropping and adding column straight after?
If it is only to make sure no such column exists, how bout this DO block:
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema='public' AND table_name='foo'
AND column_name='bar')
THEN
EXECUTE format('ALTER TABLE %I.%I ADD %I text',
'public','foo','bar');
END IF;
END; $$;
You can also create a function if you tend to do such check quite often.

How to run a sequence of SQL queries and save the results?

In other statistical programs, it's possible to create a log file that shows the output issued as a result of a command. Is it possible to do something similar in SQL?
In particular, I'd like to have a single .sql file with many queries and to then output each result to a text file.
I'm using PostgreSQL and Navicat.
plpgsql function and COPY
One way would be to put the SQL script into a plpgsql function, where you can write the individual return values to files with COPY and compile a report from intermediary results just like you need it.
This has additional effect that may or may not be desirable. Like, you can grant or revoke permission to the whole function to arbitrary roles. Read about SECURITY DEFINER in the manual. And the syntax will be verified when you save the function - however, only superficially (there are plans to change that in the future). More details in this answer on dba.SE.
Basic example:
CREATE OR REPLACE FUNCTION func()
RETURNS void AS
$BODY$
BEGIN
COPY (SELECT * FROM tbl WHERE foo) TO '/path/to/my/file/tbl.csv';
COPY (SELECT * FROM tbl2 WHERE NOT bar) TO '/path/to/my/file/tbl2.csv';
END;
$BODY$
LANGUAGE plpgsql;
Of course, you need to have the necessary privileges in the database and in the file system.
Call it from the shell:
psql mydb -c 'SELECT func();'
psql switching between meta commands and SQL
#!/bin/sh
BASEDIR='/var/lib/postgresql/outfiles/'
echo "
\\o $OUTDIR/file1.txt \\\\\\\\ SELECT * FROM tbl1;
\\o $OUTDIR/file2.txt \\\\\\\\ SELECT * FROM tbl2;
\\o $OUTDIR/file3.txt \\\\\\\\ SELECT * FROM tbl3;" | psql event -p 5432 -t -A
That's right, 8 backslashes. Results from a double backslash that gets interpreted two times, so you have to double them two times.
I quote the manual about the meta-commands \o:
Saves future query results to the file filename or ...
and \\:
command must be either a command string that is completely parsable by
the server (i.e., it contains no psql-specific features), or a single
backslash command. Thus you cannot mix SQL and psql meta-commands with
this option. To achieve that, you could pipe the string into psql,
like this: echo '\x \\ SELECT * FROM foo;' | psql. (\\ is the
separator meta-command.)
Don't know about navicat, but you can do it with psql. Check the various --echo-X command-line options and the \o command if you just want temporary output to a file.

PostgreSQL isset function

Is there any way, how to check, whether a variable has already been set in my environment?
Example:
\set table_name countries
\i queries.sql
queries.sql:
SELECT * FROM :table_name;
I want to make queries.sql to be called independently and use some default table name I would specify.
Is this possible or do I really need to create another SQL file through which I will call the queries (\i)?
My use case is usage of my SQL queries both in pgTAP unit tests (with some sample table names) and independently.
You could check the current value with:
SELECT :'table_name';
You can set it on the call to psql with something like --set='table_name' on the psql command line.