Генерация сценария SQL*Plus с использованием SQL*Plus

Я хочу сгенерировать кучу сценариев SQL*Plus, запрашивая словарь данных, но столкнулся с некоторыми проблемами и подозреваю, что упускаю что-то очевидное.

Например, когда я выполняю в SQL*Plus следующее, я получаю ORA-01756: quoted string not properly terminated:

SQL> SPOOL myscript.sql
SQL> SELECT q'[SPOOL log
  2  SELECT COUNT(*) FROM DUAL;
ERROR:
ORA-01756: quoted string not properly terminated

Я попытался использовать символ продолжения строки, чтобы избежать этой ошибки, но он помещает символ продолжения в вывод:

SQL> SELECT q'[SPOOL log
  2  SELECT COUNT(*) FROM DUAL; -
  3  PROMPT Done.
  4  ]' FROM DUAL;
SPOOL log
SELECT COUNT(*) FROM DUAL; -
PROMPT Done.

Обратите внимание, что в выводе есть - после DUAL;? Я не хочу этого в сгенерированном скрипте.

Один из способов обойти это — объединить множество вызовов функций CHR() для создания точек с запятой и перевода строки; но я надеюсь, что мне не придется этого делать, потому что эти генерируемые скрипты очень длинные, а такие биты, как ]'||CHR(59)||CHR(10)||q'[, разбросанные по всему коду, делают его очень уродливым и мучительным для устранения неполадок.

(Я использую SQL*Plus версии 11.2.0.1.0 Production, подключаясь к экземпляру 11gR2.)


person Jeffrey Kemp    schedule 10.11.2010    source источник


Ответы (5)


Проблема в том, что SQL*Plus интерпретирует ваш первый ; как терминатор команды. Вы могли заметить, что если вы записываете свои команды в текстовый файл и выполняете его (или редактируете его в текстовом редакторе из SQL*Plus), он работает.

Чтобы заставить его работать с живой печатью, если вы действительно хотите это сделать (кажется маловероятным, если они будут очень длинными!), Вы можете отключить автоматическое определение терминатора с помощью SET SQLTERMINATOR off. Обратите внимание, что вам придется сообщить SQL*Plus, что вы закончили и что он должен выполняться с инструкцией /, так как вторая ; также игнорируется.

SQL> SPOOL myscript.sql
SQL> SET SQLTERMINATOR off
SQL> SELECT q'[SPOOL log
  2  SELECT COUNT(*) FROM DUAL;
  3  PROMPT Done.
  4  ]' FROM DUAL
  5  /
SPOOL log
SELECT COUNT(*) FROM DUAL;
PROMPT Done.

Если вы строите их из словаря данных, другим вариантом является использование PL/SQL для выполнения запросов и манипуляций и dbms_output для создания вывода, который вы собираетесь буферизовать, до тех пор, пока окончательный размер файла не будет превышать пределы буфера.

person Alex Poole    schedule 10.11.2010
comment
‹хлопает себя по лбу› dbms_output! и я использую его каждый день... но спасибо и за вариант SQLTERMINATOR. - person Jeffrey Kemp; 10.11.2010
comment
(кстати, это поведение все еще происходит, когда я запускаю его из сценария.) - person Jeffrey Kemp; 10.11.2010
comment
Ах, да, конечно, SQLPlus будет интерпретировать его так же, как если бы вы его напечатали. Это нормально, если вы edit из SQL Плюс, я думаю, это обходит SQL * Net, пытающийся интерпретировать его. - person Alex Poole; 10.11.2010

Когда я хочу создать сценарий из БД, я предпочитаю писать файл с использованием пакета UTL_FILE вместо буферизации вывода SQL*Plus. Это не совсем то, что вам нужно, но я считаю, что управление доставляет гораздо меньше хлопот, чем попытка написать sql-скрипты с правильным форматированием.

person Adam Hawkes    schedule 10.11.2010
comment
Я думал об этом, но тогда мне понадобится доступ к каталогу на сервере, тогда мне нужно будет либо получить файл через FTP, либо запустить sql*plus через сеанс терминала. Я бы предпочел жить с конкатенациями CHR() :) - то, что я сейчас делаю, записывается в локальный файл, что более удобно. - person Jeffrey Kemp; 10.11.2010
comment
Я ПОЛНОСТЬЮ понимаю. Получить такой доступ в определенной среде не всегда просто. - person Adam Hawkes; 10.11.2010

Вы можете использовать getddl в пакете dbms_metada или в моем пакете: http://github.com/xtender/XT_SVN

person Sayan Malakshinov    schedule 10.11.2010
comment
getddl подходит только для создания DDL, о котором знает Oracle. Я хочу создавать свои собственные сценарии — в комплекте с SET-командами, PROMPT, запросами, DML и т. д. - person Jeffrey Kemp; 10.11.2010

Вам необходимо увидеть http://download.oracle.com/docs/cd/A97630_01/server.920/a90842/ch13.htm

SET CMDS[EP] {;|c|ON|OFF}

Sets the non-alphanumeric character used to separate multiple SQL*Plus commands entered on one line to c. ON or OFF controls whether you can enter multiple commands on a line. ON automatically sets the command separator character to a semicolon (;).
person Sayan Malakshinov    schedule 10.11.2010

Для дальнейшего использования вместо того, чтобы возиться с SET SQLTERMINATOR off при использовании sql plus, используйте следующее ниже, чтобы вам не нужно было беспокоиться о каком-либо специальном символе терминатора sql внутри тела строкового литерала.

BEGIN
INSERT INTO SOME_TABLE (q'[ 

Now;
You;
Can '
Do "'"';' ;;;
any character? *

]');
END;
/
person Chad    schedule 11.06.2014
comment
Не знаете, зачем вставлять скрипт в таблицу...? - person Jeffrey Kemp; 11.06.2014