DOC.PROTOTYPES.RU

Главная > Базы данных > PostgreSQL > Дополнения > dblink >
Имя

dblink_open - открывает курсор на таблице на внешнем сервере PostgreSQL

Синтаксис
SQL код (1)
SELECT dblink_open([ имя соединения ]::text, [ имя курсора ]::text, [ SQL запрос ]::text, [ остановка в случае ошибки ]::boolean);
Описание

dblink_open открывает курсор на внешней базе данных, который впоследствии может быть использован в функциях dblink_fetch и dblink_close.

Это значит, что по сути запрос мы отправили, но данные не получили, так как выбирать их будем позднее, что удобно если скажем, мы выбираем эти строки в стороннем цикле, как показано в примере (2):

Аргументы

имя соединения - не обязательный текстовый параметр, имя подключения dblink. Если же данный параметр опущен, то запрос отправляется на неименованную подключенную внешнюю базу данных;

имя курсора - обязательный параметр, имя курсора;

SQL запрос - обязательный параметр, SELECT запрос к внешней базе данных;

остановка в случае ошибки - не обязательный логический параметр, Если он указан как TRUE (что является умолчательным значением когда данный параметр опущен), то ошибка возвращаемая в случае неправильного выполнения удаленного запроса применяется и локально, при FALSE же ошибка выводится только лишь в качестве уведомления, а функция возвращает 0 строк.

Возвращаемые данные

Возвращает статус, либо 'ОК' или ошибку.

Примечание

Поскольку курсор может сохраняться только в течение транзакции, dblink_open запускает блока транзакции (BEGIN) на удаленной машине, если удаленная сторона в данный момент не находится в другом блоке транзакции. Эта тразакция будет закрыта, когда мы выполним соответствующее dblink_close. Замечу, что если вы используете dblink_exec для изменения данных между dblink_open и dblink_close или вы используете dblink_disconnect до dblink_close, то ваши изменения будут потеряны, так как тразнакция будет прервана. Кстати, это видно в примере (2), вставка записей в таблицу возможна только после того как курсор на ней закрыт.

Имена курсоров уникальны в пределах отдельного соединения, то есть могут сущестовать два курсора с одинаковыми именами, но для разных соединений.

Примеры
SQL код (2)
-- Функция для синхронизации двух таблиц в разных базах данных
CREATE OR REPLACE FUNCTION sync_table()
    RETURNS TEXT AS
$BODY$
DECLARE
    res         TEXT;
    t_row_01    RECORD;
    t_row_02    RECORD;
    sql_insert  TEXT;
    t_rows_01   TEXT[];
BEGIN
-- Соединяемся с внешними базами данных
    SELECT dblink_connect('rdb_01', 'remote_db_01') INTO res;
    SELECT dblink_connect('rdb_02', 'remote_db_02') INTO res;
-- Открываем курсор к первой таблице
    SELECT dblink_open('rdb_01', 'cursor_01', 'SELECT * FROM mytable ORDER BY title') INTO res;
-- и берем первую строку
    SELECT * INTO t_row_01 FROM dblink_fetch('rdb_01', 'cursor_01', 1) AS t(title TEXT);
-- Открываем цикл для второй таблицы
<<main_for>>
    FOR t_row_02 IN SELECT * FROM dblink('rdb_02', 'SELECT * FROM mytable ORDER BY title') AS t(title TEXT) LOOP
        IF t_row_01.title < t_row_02.title THEN
<<while_dblink_fetch>>
            WHILE t_row_01.title < t_row_02.title AND t_row_01.title IS NOT NULL LOOP
                sql_insert := 'INSERT INTO mytable (title) VALUES (' || quote_literal(t_row_01.title) || ');';
                SELECT dblink_exec('rdb_02', sql_insert) INTO res;
                SELECT * INTO t_row_01 FROM dblink_fetch('rdb_01', 'cursor_01', 1) AS t(title TEXT);
            END LOOP while_dblink_fetch;
        END IF;
        IF t_row_01.title > t_row_02.title OR t_row_01.title IS NULL THEN
            sql_insert := 'INSERT INTO mytable (title) VALUES (' || quote_literal(t_row_02.title) || ');';
            t_rows_01 := array_append(t_rows_01, sql_insert);
        ELSE
-- Иначе берем следующую строку из первой таблицы и переходим на следующий цикл
            SELECT * INTO t_row_01 FROM dblink_fetch('rdb_01', 'cursor_01', 1) AS t(title TEXT);
        END IF;
    END LOOP main_for;
-- Но у нас курсор может быть не на последней строке
    SELECT * INTO t_row_01 FROM dblink_fetch('rdb_01', 'cursor_01', 1) AS t(title TEXT);
-- Добираем оставшиеся записи из первой таблицы
    WHILE t_row_01.title IS NOT NULL LOOP
        sql_insert := 'INSERT INTO mytable (title) VALUES (' || quote_literal(t_row_01.title) || ');';
        SELECT dblink_exec('rdb_02', sql_insert) INTO res;
        SELECT * INTO t_row_01 FROM dblink_fetch('rdb_01', 'cursor_01', 1) AS t(title TEXT);
    END LOOP;
-- Закрываем курсор    
    SELECT dblink_close('rdb_01', 'cursor_01') INTO res; 
-- Теперь можно добавлять данные в таблицу
    FOR sql_insert IN SELECT * FROM unnest(t_rows_01) LOOP
        SELECT dblink_exec('rdb_01', sql_insert) INTO res;
    END LOOP;
-- Разъединяемся с внешними базами данных
    SELECT dblink_disconnect('rdb_01') INTO res;
    SELECT dblink_disconnect('rdb_02') INTO res;
    RETURN 'OK';
END;
$BODY$
    LANGUAGE 'plpgsql' VOLATILE
    COST 100;
Оригинал

http://www.postgresql.org/docs/8.4/static/contrib-dblink-open.html

Сергей Томулевич aka Phoinix (30.09.2009 г.)
Valid HTML 4.01 Transitional
Copyright © 2011 Сергей Томулевич