2013-08-19 32 views
6

Ich verwende dblink, um bestimmte Daten zwischen Datenbanken zu verschieben. Alles ist sicher und zuverlässig, aber ich frage mich, ob es eine bequemere Möglichkeit gibt, die Spaltendefinitionsliste eines dblink-Abfrageergebnisses zu definieren. Ich kann so etwas tun:Angeben der dblink-Spaltendefinitionsliste von einem lokalen vorhandenen Typ

SELECT * 
FROM dblink('dbname=remote', 'select * from test') 
AS t1(id integer, data text); 

Die Tabellen mir die Interaktion mit der gleichen Schema-Definition in beiden Datenbanken (remote & lokal). Ich dachte an so etwas wie:

SELECT * 
FROM dblink('dbname=remote', 'select * from test') 
AS t1 LIKE public.test; 

Oder:

SELECT * 
FROM dblink('dbname=remote', 'select * from test') 
AS t1::public.test; 

Die Spaltendefinitionsliste neigt ziemlich lang geworden. Gibt es etwas, das ich übersehen habe?

EDIT:

Da dies ein Problem für mich war, bevor ich eine kleine Funktion als Behelfslösung erstellt.

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$; 

Diese Funktion erstellt und liefert eine Funktion, die den dblink-Aufruf umschließt. Es ist sicherlich nicht für schweres Heben, sondern für Bequemlichkeit. Es wäre schön, wenn es sich herausstellt, dass es überhaupt nicht notwendig ist.

> 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) 
+0

Ich brauche deine Hilfe. Ich versuche zu tun, was Sie ursprünglich gefragt haben, aber ich kann meinen Weg nicht finden ... –

+0

Ich kämpfe, um eine Version Ihres ehrfürchtigen Codes ohne Zwischenfunktion ('dblink_star_func') zu machen, um abfragen zu können 'wähle * aus select_remote ('dbname = ben', 'public', 'test'), wobei data = 'success'; Könnten Sie sich meine Frage dort anschauen: http://stackoverflow.com/questions/25691511/postgresql-error-structure-of-query-does-not-match-function-result-type-using? Danke –

Antwort

1

Unter Umständen müssen Sie sicherstellen, dass Ihre Typen immer synchron sind, aber dies sollte funktionieren:

SELECT (t1::test).* 
    FROM dblink('dbname=remote', 'select * from test') AS t1; 

Der Schlüssel ist, dass oft Sie Klammern, um sicherzustellen, müssen, dass der Parser weiß, dass Sie es zu tun Tupel.

Zum Beispiel funktioniert das für mich:

CREATE TABLE test (id int, test bool); 
select (t1::test).* from (select 1, true) t1; 

Aber dies einen Syntaxfehler führt:

select t1::test.* from (select 1, true) t1; 
+5

Es funktioniert nicht in 'dblink' (Postgres 9.1). Wirft den Fehler 'eine Spaltendefinitionsliste ist für Funktionen erforderlich, die" record "zurückgeben' – ADTC

+0

@ADTC Lustige Sache, die ich herkam, weil Änderung von 'dblink' Funktion zu' dblink_connect' und jetzt nicht funktioniert. –

+0

Siehe die Lösung von @ Rémy Baron unten. Das funktioniert in Postgres 9.6. – kirikaza

4

so etwas wie dieses Versuchen:

select (rec).* from dblink('dbname=...','select myalias from foreign_table 
    myalias') t1 (rec local_type) 

Beispiel (get Tabellen Statistiken aus andere Datenbank):

select (rec).* from dblink('dbname=foreignDb','select t1 from 
    pg_stat_all_tables t1') t2 (rec pg_stat_all_tables)