Selecting column name from other database table through function in PostgreSQL - postgresql

Here i need to select a column name by using function(stored procedure) which is present in other database table using PostgreSQL.
I have sql server query as shown below.
Example:
create procedure sp_testing
as
if not exists ( select ssn from testdb..testtable) /*ssn is the column-name of testtable which exists in testdb database */
...
Q: Can i do the same in PostgreSQL?

Your question is not very clear, but if you want to know if a column by a certain name exists in a table by a certain name in a remote PostgreSQL database, then you should first set up a foreign data wrapper, which is a multi-stage process. Then to test the existence of a certain column in a table you need to formulate a query that conforms to the standards of the particular DBMS that you are connecting to. Use the remote information_schema.tables table for optimal compatibility (which is here specified as remote_tables which you must have defined with a prior CREATE FOREIGN TABLE command):
CREATE FUNCTION sp_testing () AS $$
BEGIN
PERFORM *
FROM remote_tables
WHERE table_name = 'testtable'
AND column_name = 'ssn';
IF NOT FOUND THEN
...
END IF;
END;
$$ LANGUAGE plpgsql;
If you want to connect to another type of DBMS, you need to write some custom function in f.i. C or perl and then call that from within a PostgreSQL function on your local machine. The test on the column is then best done inside the function which should therefore take connection parameters, table name and column name as parameters, and return a boolean to inform the result.
Before you start testing this, make sure that you read all the documentation on connecting to remote servers and learning PL/pgSQL first would also be a nice gesture to demonstrate your own efforts before you ask for help.

Related

Can I create and access a table in the same SQL function?

I am trying to create a Postgres SQL-function which runs some routine for my database.
The SQL-function calls a plpgsql-function which creates several temporary tables, but doesn't return anything (RETURNS void).
One of the tables created by the plpgsql-function is supposed to be used in my sql-function.
CREATE OR REPLACE FUNCTION public.my_sql_function()
RETURNS text AS
$BODY$
select public.my_plpsql_function(); -- this returns void, but has created a temp table "tmp_tbl"
DROP TABLE IF EXISTS mytable CASCADE;
CREATE TABLE mytable (
skov_id int8 PRIMARY KEY,
skov_stor int4,
skov_areal_ha numeric,
virkningfra timestamp(0) without time zone,
plannoejagtighed float8,
vertikalnoejagtighed float8,
geom geometry(MultiPolygon,25832),
orig_geom geometry(Polygon, 25832)
);
INSERT INTO mytable
select * from tmp_tbl ....
$BODY$ LANGUAGE sql;
When I try to run the lines, I get the following error:
ERROR: relation "tmp_tbl" does not exist
pgAdmin underlines the line select * from tmp_tbl ... as the part with an error.
So the SQL-function doesn't notice that the plpsql-function has created a temporary table.
Is there a workaround?
Creating and accessing a table in the same SQL function is generally impossible. Makes no difference whether you create the table in the SQL function directly or in a nested function call. All objects must be visible to begin with.
There is a big, fat note at the top of the chapter Query Language (SQL) Functions in the manual pointing that out:
Note
The entire body of a SQL function is parsed before any of it is
executed. While a SQL function can contain commands that alter the
system catalogs (e.g., CREATE TABLE), the effects of such commands
will not be visible during parse analysis of later commands in the
function. Thus, for example, CREATE TABLE foo (...); INSERT INTO foo VALUES(...); will not work as desired if packaged up into a single
SQL function, since foo won't exist yet when the INSERT command is
parsed. It's recommended to use PL/pgSQL instead of a SQL function in
this type of situation.
Related:
Why can PL/pgSQL functions have side effect, while SQL functions can't?
Difference between language sql and language plpgsql in PostgreSQL functions
I think so it is not possible - and minimally it should not by possible in future versions. SQL functions are similar to views, and then references to database object should be valid in function's creating time.
There is not any workaround - if you need temp table, use PLpgSQL, or try to write your code without temp table (it can be much better).

temp tables in postgresql

I'm coming from a background in SQL Server where I would create temp tables using the:
select id
into #test
from table A
I've just moved into a PostGresql environment and I was hoping I could do the same, but I'm getting a syntax error. I did a search and it seems like you have to do a Create Table statement.
Is it not possible to easily create temp tables in Postgres?
Postgres supports SELECT INTO, so this should work fine:
SELECT id
INTO TEMP TABLE test
FROM a
You can also use CREATE TABLE AS:
CREATE TEMP TABLE test AS
SELECT id FROM a
This version is generally preferred, as the CREATE statement provides additional options, and can also be used in PL/pgSQL functions (where the SELECT INTO syntax has been hijacked for variable assignment).

Extracting a table name after installing a extension module in postgreSQL?

So the thing is I am developing a contrib module and want to capture table name inside that contrib module.
question:
Is there any way to capture a table name during create table or insert table?
I have seen some of the triggers but not able to make it (I don't think there is any create table trigger). In case it is possible tell me a way to achieve it.
I though of extracting meta-data using pg_class but not helping it seems because I have to give explicitly a rel-name (table name) in where clause
do you think any other way to achieve it? Please elaborate if any and please let me know.
Here is some example which will make you understand a bit about the things I want to achieve.
creating a table:
create table new_table(name varchar , new integer);
insert into new_table values('abcdefghijkl' , 5004);
create table new_table1(name1 varchar , new1 integer) ;
insert into new_table1 values('mnopqrst' , 5005);
creating extension:
create extension table_name-extract;
select extract_tablename();
So my extension should extract a table name, means I should know table name with the built-in datatype I have declared.
Here what I expect as a output:
select extract_tablename();
table-name datatype-name
new_table name new
new_table1 name1 new1
You don't really need an extension to track the execution of DDL statements.
For that you can use an event trigger
The manual also has an example on how to write an event trigger using PL/pgSQL
CREATE OR REPLACE FUNCTION snitch()
RETURNS event_trigger
AS $$
BEGIN
RAISE NOTICE 'snitch: % %', tg_event, tg_tag;
END;
$$ LANGUAGE plpgsql;
CREATE EVENT TRIGGER snitch ON ddl_command_start
EXECUTE PROCEDURE snitch();
Inside the trigger function you would need to store the table name in some configuration table so that the information is not lost.
Of course you can package your trigger and "log table" (as a configuration table) into an extension if you want.
Another option is to enable DDL logging using
log_statement=ddl
in postgresql.conf - then you have all DDL statements in the Postgres logfile.

Create non conflicting temporary tables in a Pl/pgSQL function

I want to create a TEMPORARY TABLE in a Pl/pgSQL function because I want to index it before doing some process. The fact that any concurrent call to the function will try to reuse the same table seems to be a problem.
e.g. A first call to the function creates and uses a temporary table named "test" with data depending on the function parameters. A second concurrent call tries also to create and use the temporary table with the same name but with different data...
The doc says
"Temporary tables are automatically dropped at the end of a session,
or optionally at the end of the current transaction"
I guess the problem would not exist if temporary tables created with the "ON COMMIT DROP" option would only be visible to the current transaction. Is this the case?
If not, how to automatically create independent tables from two different function calls?
I could probably try to create a temporary name and check if a table with this name already exists but that seems like a lot of management to me...
Temporary tables of distinct sessions cannot conflict because each session has a dedicated temporary schema, only visible to the current session.
In current Postgres only one transaction runs inside the same session at a time. So only two successive calls in the same session can see the same temporary objects. ON COMMIT DROP, like you found, limits the lifespan of temp tables to the current transaction, avoiding conflicts with other transactions.
If you (can) have temp tables that don't die with the transaction (like if you want to keep using some of those tables after the end of the current transaction), then an alternative approach would be to truncate instead of create if the temp table already exists - which is a bit cheaper, too.
Wrapped into a function:
CREATE OR REPLACE FUNCTION f_create_or_trunc_temp_table(_tbl text, OUT _result "char") AS
$func$
BEGIN
SELECT INTO _result relkind
FROM pg_catalog.pg_class
WHERE relnamespace = pg_my_temp_schema() -- only temp objects!
AND relname = _tbl;
IF NOT FOUND THEN -- not found
EXECUTE format('CREATE TEMP TABLE %I(id int)', _tbl);
ELSIF _result = 'r' THEN -- table exists
EXECUTE format('TRUNCATE TABLE %I', _tbl); -- assuming identical table definition
ELSE -- other temp object occupies name
RAISE EXCEPTION 'Other temp object of type >>%<< occupies name >>%<<', _result, _tbl;
-- or do nothing, return more info or raise a warning / notice instead of an exception
END IF;
END
$func$ LANGUAGE plpgsql;
Call:
SELECT f_create_or_trunc_temp_table('my_tbl');
This assumes identical table definition if the table exists. You might do more and also return more informative messages, etc. This is just the basic concept.
Related:
How can I determine if a table exists in the current search_path with PLPGSQL?
How to check if a table exists in a given schema
Temporary tables are visible only in the current session. Concurrent processes do not see each other's temporary tables even when they share the same names. Per the documentation:
PostgreSQL requires each session to issue its own CREATE TEMPORARY TABLE command for each temporary table to be used. This allows different sessions to use the same temporary table name for different purposes (...)

Copy data between two tables in PostgreSQL using dblink.sql

I am using PostgreSQL 9.1. I need to transfer required columns from one table of one database into another table of another database, but not schema.
I found that dblink.sql file has to be there in share/contrib. But my contrib folder is empty. Where can I download the dblink.sql file and can execute my query?
When I execute the query now it shows an error message:
cross database reference is not possible ...
Can anyone help me how to transfer the data between two databases?
After you have installed the package into your system as detailed in the related question install the extension dblink into your database (the one you are running this code in, the foreign db does not need it):
CREATE EXTENSION dblink;
You can find code examples in the manual.
Here is a simple version of what I use to copy data between dbs:
First, create a FOREIGN SERVER
CREATE SERVER mydb
FOREIGN DATA WRAPPER postgresql
OPTIONS (hostaddr '111.111.111.111',port '5432',dbname 'mydb');
FOREIGN DATA WRAPPER postgresql was pre-installed in my case.
Then create function that opens a connection, removes old data (opotional), fetches new data, runs ANALYZE and closes the connection:
CREATE OR REPLACE FUNCTION f_tbl_sync()
RETURNS text AS
$BODY$
SELECT dblink_connect('mydb'); -- USER MAPPING for postgres, PW in .pgpass
TRUNCATE tbl; -- optional
INSERT INTO tbl
SELECT * FROM dblink(
'SELECT tbl_id, x, y
FROM tbl
ORDER BY tbl_id')
AS b(
tbl_id int
,x int
,y int)
ANALYZE tbl;
SELECT dblink_disconnect();
$BODY$
LANGUAGE sql VOLATILE;