PostgreSQL: создать внешнюю таблицу со строкой и переменной

Моя проблема: мне нужно динамически определять внешнюю таблицу и каждый раз устанавливать разные условия. Я делаю это в функции, но получаю ошибку, которая не имеет для меня смысла во время создания внешней таблицы (через oracle_fdw).

Создание внешней таблицы, которая работает:

CREATE FOREIGN TABLE MYFOREIGNTABLE 
(
column1 int,
column2 text
)
SERVER fwdb
OPTIONS (table $$(
  select
    column1,
    column2
  from
    table1
  where 
   column3 = 5
   and column4 = 'a'
)$$);

Теперь, если я попытаюсь разбить строку, чтобы поместить туда свои переменные (вместо переменной я оставил там номер, чтобы кто-нибудь мог попробовать), она перестанет работать, и я получаю сообщение об ошибке.

[Код: 0, состояние SQL: 42601] ОШИБКА: синтаксическая ошибка в или около ||

CREATE FOREIGN TABLE MYFOREIGNTABLE 
(
column1 int,
column2 text
)
SERVER fwdb
OPTIONS (table $$(
  select
    column1,
    column2
  from
    table1
  where 
   column3 = $$ || 5 || $$
   and column4 = 'a'
)$$);

Наверняка я попробовал свою строку в select, чтобы убедиться, что я не сделал синтаксической ошибки, и она работает без проблем.

select $$(
  select
    column1,
    column2
  from
    table1
  where 
   column3 = $$ || 5 || $$
   and column4 = 'a'
)$$

Я пробовал несколько других вещей, таких как использование concat() или помещение всей строки в переменную OPTIONS (table myvariable);, но ничего не работало. Какой здесь правильный синтаксис?

PostgreSQL 11.10 на x86_64-pc-linux-gnu, скомпилированный gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39), 64-разрядная версия


person Baker    schedule 01.12.2020    source источник
comment
Какую стороннюю оболочку данных вы используете? oracle_fdw?   -  person Laurenz Albe    schedule 02.12.2020
comment
да, это oracle_fdw для подключения к базе данных оракула   -  person Baker    schedule 02.12.2020


Ответы (1)


Вы должны использовать строковый литерал в качестве значения для параметра FDW, такие выражения, как конкатенация строк, которые вы пытаетесь использовать, не допускаются.

Вам нужно будет построить полный оператор с динамическим SQL, например

DO
$$DECLARE
   var integer := 5;
BEGIN
   EXECUTE
      format(
         E'CREATE FOREIGN TABLE MYFOREIGNTABLE (\n'
         '   column1 int,\n'
         '   column2 text\n'
         ') SERVER fwdb OPTIONS (\n'
         '   table ''(SELECT column1,\n'
         '                   column2\n'
         '            FROM table1\n'
         '            WHERE column3 = %s\n'
         '              AND column4 = ''''a'''')'')',
         var
      );
END;$$;

Для строковых переменных вы должны получить правильное цитирование, используя quote_literal(quote_literal(var)).

person Laurenz Albe    schedule 02.12.2020
comment
Спасибо, это работает, но не могли бы вы объяснить мне, что означает E в начале? А также можно ли заменить ' на $$ в качестве строки в кавычках? - person Baker; 02.12.2020
comment
E — это расширенный строковый литерал, и я использую его только для того, чтобы написать \n для новой строки. Вы можете написать весь запрос в одной строке, если хотите. Конечно, вы можете использовать кавычки в долларах, но вам нужно использовать кавычки, отличные от окружающих $$, например, $query$. Это может быть лучше, потому что тогда у вас будет только один уровень двойных кавычек. - person Laurenz Albe; 02.12.2020