I am using dblink to move certain data between databases. Everything is save and sound but I am wondering if there is a more convenient way to define the column definition list of a dblink query result. I can do something like this:
SELECT *
FROM dblink('dbname=remote', 'select * from test')
AS t1(id integer, data text);
The tables I'm interacting with have the same schema definition in both databases (remote & local). I was thinking of something like:
SELECT *
FROM dblink('dbname=remote', 'select * from test')
AS t1 LIKE public.test;
Or:
SELECT *
FROM dblink('dbname=remote', 'select * from test')
AS t1::public.test;
The column definition list tends to become quite long. Is there something I may have overlooked?
EDIT:
As this has been a problem for me before I created a small function as a work-around.
CREATE OR REPLACE FUNCTION dblink_star_func(_conn text, _schema_name text, _table_name text)
RETURNS text
LANGUAGE PLPGSQL
VOLATILE STRICT
AS $function$
DECLARE
_dblink_schema text;
_cols text;
_q text;
_func_name text := format('star_%s', $3);
_func text;
BEGIN
SELECT nspname INTO _dblink_schema
FROM pg_namespace n, pg_extension e
WHERE e.extname = 'dblink' AND e.extnamespace = n.oid;
SELECT array_to_string(array_agg(column_name || ' ' || udt_name), ', ') INTO _cols
FROM information_schema.columns
WHERE table_schema = $2 AND table_name = $3;
_q := format('SELECT * FROM %I.dblink(%L, %L) AS remote (%s)',
_dblink_schema,
_conn,
format('SELECT * FROM %I.%I', $2, $3),
_cols
);
_func := $_func$
CREATE OR REPLACE FUNCTION %s()
RETURNS SETOF %I.%I
LANGUAGE SQL
VOLATILE STRICT
AS $$ %s; $$
$_func$;
EXECUTE format(_func, _func_name, $2, $3, _q);
RETURN _func_name;
END;
$function$;
This function creates and yields a function that wraps the dblink call. It's certainly not meant for heavy lifting but convenience.It would be nice if it turns out it's not necessary at all.
> select dblink_star_func('dbname=ben', 'public', 'test');
┌──────────────────┐
│ dblink_star_func │
├──────────────────┤
│ star_test │
└──────────────────┘
(1 row)
> select * from star_test() where data = 'success';
┌────┬─────────┐
│ id │ data │
├────┼─────────┤
│ 1 │ success │
└────┴─────────┘
(1 row)
You might need to make sure that your types are always in sync but this should work:
SELECT (t1::test).*
FROM dblink('dbname=remote', 'select * from test') AS t1;
The key is that often you need parentheses to ensure that the parser knows you are dealing with tuples.
For example this works for me:
CREATE TABLE test (id int, test bool);
select (t1::test).* from (select 1, true) t1;
But this throws a syntax error:
select t1::test.* from (select 1, true) t1;
Try something like this :
select (rec).* from dblink('dbname=...','select myalias from foreign_table
myalias') t1 (rec local_type)
Example (get tables stats from other database) :
select (rec).* from dblink('dbname=foreignDb','select t1 from
pg_stat_all_tables t1') t2 (rec pg_stat_all_tables)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With