сгенерировать файл Excel с помощью курсора в анонимном блоке в оракуле

У меня ниже анонимный блок, где я использую курсор для создания набора результатов и сохранения его в файл TEST_REPORT.csv. Но я получаю сообщение об ошибке в строке, где я использую катушку как:

PLS-00103: Encountered the symbol "H" when expecting one of the following:
   := . ( @ % ;

Я считаю, что не могу использовать катушку в PL / SQL, но не уверен, поэтому я попробовал код ниже. А также я не могу использовать логику UTL_FILE или UTL_FILE_DIR из-за ограничения безопасности на производстве. Поскольку сотрудники работают в разных отделах, я хочу создать отдельный файл CSV для каждого сотрудника по отношению к их отделу.

Есть ли способ сломать этот код и использовать спул для создания файла csv или любой другой логики? Также, если невозможно использовать спул в анонимном блоке, могу ли я использовать его во время выполнения этого кода для создания файлов?

Если это невозможно с использованием спула, возможно ли, если я смогу организовать свой результат запроса таким образом, чтобы было легко экспортировать результат в один файл csv после выполнения этого анонимного блока, а затем я могу разделить один файл csv на несколько файлы в зависимости от сотрудника с его отделом вручную?

Файл Generate-And-Run.sql

SET SERVEROUTPUT ON;
set verify off
SET LONG 100000
SET lines 1000 
SET sqlformat SELECT;
SPOOL C:\Loop-Flattener.sql;

PROMPT VAR V_A VARCHAR2(64);


BEGIN
  FOR TARGET_POINTER IN (select ID,
       name,
       ST_ID      
from TEST_REPORT
where rownum <5)
    LOOP
    DBMS_OUTPUT.PUT_LINE('DEFINE TARGET = '''||TARGET_POINTER.ID||''';');
    DBMS_OUTPUT.PUT_LINE('EXEC :V_A := '''||TARGET_POINTER.ID||'''; ');
    DBMS_OUTPUT.PUT_LINE('@@Target-Csv-Generator.sql;');
  END LOOP;
END;
/

SPOOL OFF;

person Andrew    schedule 03.09.2017    source источник


Ответы (2)


Как упоминал OldProgrammer, вы не можете вызывать SPOOL в PL/SQL. Но вы можете печатать в буферный файл из PL/SQL, а также можете предварительно скомпилировать / сгладить цикл в делегирующий промежуточный рабочий скрипт, который неоднократно вызывает csv-generator.

Обновить. В ответ на предоставленную вами конкретную информацию вам должно подойти следующее.

Пример данных испытаний:

INSERT INTO CSS_BOUTIQUE VALUES ('EUR', 'Belgium', 'a0Hb0000006LLdQ');
INSERT INTO CSS_BOUTIQUE VALUES ('EUR', 'Portugal', 'a0HB0000006LLOG');
INSERT INTO CSS_BOUTIQUE VALUES ('EUR', 'Portugal', 'a0HB0000006LLYu');

INSERT INTO CSS_BOUTIQUE VALUES ('ASIA', 'Korea', 'e0HB0000016MEIi');
INSERT INTO CSS_BOUTIQUE VALUES ('ASIA', 'China', 'e0HB0000026MEIi');
INSERT INTO CSS_BOUTIQUE VALUES ('ASIA', 'Japan', 'e0HB0000036MEIi');

INSERT INTO CSS_BOUTIQUE VALUES ('SA', 'Chile', 's0HB0000016MEIi');
INSERT INTO CSS_BOUTIQUE VALUES ('SA', 'Argentina', 's0HB0000026MEIi');
INSERT INTO CSS_BOUTIQUE VALUES ('SA', 'Equador', 's0HB0000036MEIi');

Затем создайте следующие два сценария:

Generate-And-Run.sql Этот сценарий создаст плоский псевдо-цикл путем создания промежуточного сценария, заполненного итеративными командами для установки новых имен переменных и вызова повторно используемого генератора csv.

SET ECHO OFF;
SET FEEDBACK OFF;
SET HEAD OFF;
SET LIN 256;
SET TRIMSPOOL ON;
SET WRAP OFF;
SET PAGES 0;
SET TERM OFF;
SET SERVEROUTPUT ON;

SPOOL Loop-Flattener.sql;

PROMPT VAR V_ZONE_NAME VARCHAR2(64);


BEGIN
  FOR TARGET_POINTER IN (SELECT DISTINCT ZONE FROM CSS_BOUTIQUE)
    LOOP
    DBMS_OUTPUT.PUT_LINE('DEFINE TARGET = '''||TARGET_POINTER.ZONE||''';');
    DBMS_OUTPUT.PUT_LINE('EXEC :V_ZONE_NAME := '''||TARGET_POINTER.ZONE||'''; ');
    DBMS_OUTPUT.PUT_LINE('@@Target-Csv-Generator.sql;');
  END LOOP;
END;
/

SPOOL OFF;

@@Loop-Flattener.sql;

Target-Csv-Generator.sql: этот скрипт выполняет работу по созданию одного CSV-файла. Обратите внимание, что имя отчета здесь - это простой REPORT_FOR... без какого-либо дополнительного пути, чтобы гарантировать, что он будет создан в рабочем каталоге.

SPOOL REPORT_FOR_&&TARGET..csv;

PROMPT zone,market, boutique_id;

select zone||','||
       market||','||
       boutique_id      
from CSS_BOUTIQUE
where rownum <5 and ZONE = :V_ZONE_NAME;

SPOOL OFF;

Затем запустите:

Поместите два вышеуказанных сценария в каталог, в котором вы хотите создать свои CSV-файлы, затем Запустите SQLPlus в этом каталоге.

SQL*Plus: Release 12.2.0.1.0 Production on Sun Sep 10 14:38:13 2017
SQL> @@Generate-And-Run

Теперь в рабочем каталоге есть три новых файла:

REPORT_FOR_EUR.csv
REPORT_FOR_SA.csv
REPORT_FOR_ASIA.csv

И у каждого есть данные только для своей зоны. Например:

cat REPORT_FOR_ASIA.csv 

Урожайность:

zone,market, boutique_id
ASIA,Korea,e0HB0000016MEIi
ASIA,China,e0HB0000026MEIi
ASIA,Japan,e0HB0000036MEIi
person alexgibbs    schedule 03.09.2017
comment
Я пробовал ваш метод, который очень полезен и генерирует файл с результатом запроса. Я упомянул свой код, о котором идет речь. Но единственное, что теперь мне нужно создать отдельный файл для каждого сотрудника в соответствии с его отделом. В настоящее время он печатает все в одном файле. Вот почему я хочу использовать цикл в коде - person Andrew; 04.09.2017
comment
Спасибо @Andrew. Это интересно. Хорошая новость в том, что вы все еще можете использовать sqlplus для этого, сглаживая цикл. Вместо одного скрипта с одной катушкой вы можете использовать два - повторно используемый скрипт, подобный этому, для буферизации деталей, который использует переменную подстановки для имени файла и привязку (и) для параметров запроса, а также можно использовать любой из вышеперечисленных подходов. для спулинга первого мастер-скрипта, который сглаживает цикл - он устанавливает параметр запроса и имя файла для каждой цели и вызывает повторно используемый скрипт в большом списке. Я ухожу от своего компьютера до завтра, но тогда я могу обновить его с помощью рабочего примера. Спасибо - person alexgibbs; 04.09.2017
comment
спасибо за ответ Алекс. Я буду ждать вашего рабочего примера, а тем временем я попробую то же самое. И я также хотел бы знать, поскольку у меня нет доступа к sqlplus. Могу ли я использовать логику, о которой вы говорите в sql-разработчике? - person Andrew; 05.09.2017
comment
Я нашел здесь один пример. Вы имели в виду то же самое? stackoverflow.com/questions/25184216/ Также я хочу параметризовать в моем случае ID, Department_name и application_date. - person Andrew; 05.09.2017
comment
Спасибо @Andrew. Да, упомянутый вопрос имеет аналогичный подход - автоматическое создание сценария оболочки, а затем вызов оболочки. Это то, что я имел в виду при компиляции цикла. Я обновлю пример сейчас. Спасибо - person alexgibbs; 05.09.2017
comment
@Andrew обновлен пример. Вам подходит этот подход? - person alexgibbs; 05.09.2017
comment
Привет, Алекс, спасибо за ответ, который действительно мне нужен. Я пробовал ваш метод таким же образом, изменяя свой запрос, но не генерируя файл excel - person Andrew; 05.09.2017
comment
Я думаю, что переменная привязки не назначается файлу Target-Csv-Generator.sql - person Andrew; 06.09.2017
comment
Также я думаю, что этот код будет генерировать файл Excel для каждой строки, которую возвращает файл Generate-And-Run.sql, верно? Потому что, например, мне нужно создать и отфильтровать это в зависимости от уникального отдела. Таким образом, в одном отделе может быть много сотрудников - person Andrew; 06.09.2017
comment
Спасибо @Andrew. В этом примере создается один CSV для каждой строки, но вы можете агрегировать данные и параметризовать их нечеткими значениями, такими как department_id. Трудно догадаться, что происходит, не видя задействованных данных. Можете ли вы обновить структуру EMPLYOEE_MARKET с помощью небольшого количества тестовых данных и, возможно, запланированного вывода csvs из тестовых данных? Я могу взглянуть на детали. Спасибо - person alexgibbs; 06.09.2017
comment
мы можем обсудить это в чате, где я покажу вам свой код, который я пытаюсь сделать? Когда я запускаю @ Generate-And-Run, он генерирует следующий код в Loop-Flattener.sql: VAR V_A VARCHAR2 (64) анонимный блок завершен DEFINE TARGET = 'AU'; EXEC: V_A: = 'AU'; C: \ CKLR_REPORT \ Target-Csv-Generator.sql; ОПРЕДЕЛИТЬ ЦЕЛЬ = 'AU'; EXEC: V_A: = 'AU'; C: \ CKLR_REPORT \ Target-Csv-Generator.sql; ОПРЕДЕЛИТЬ ЦЕЛЬ = 'AU'; EXEC: V_A: = 'AU'; C: \ CKLR_REPORT \ Target-Csv-Generator.sql; - person Andrew; 06.09.2017
comment
Но я не знаю, по какой причине CSV не создается в каталоге. Я думаю, что это не вызов Target-Csv-Generator.sql должным образом, не уверен. Если он создаст csv, моя проблема будет решена, и, как вы сказали, я наложу ограничения позже. Если я поставлю: V_A vaule непосредственно в Target-Csv-Generator.sql, тогда он создаст файл Excel. Я запускаю этот код в sql-разработчике, это проблема из-за этого? - person Andrew; 06.09.2017
comment
Спасибо @Andrew Меня беспокоит грубое C:\CKLR_REPORT\Target-Csv-Generator.sql; в содержании Loop-Flattener.sql. SQLPlus не должен запускать это без @ или @@ перед скриптом Csv-Generator. (в своем ответе я запустил SQLPlus в рабочем каталоге с @@Target-Csv-Generator.sql;). Можете ли вы попробовать поместить вещи в рабочий каталог и отбросить полные пути C: \ CKLR .... и просто запустить SQLPlus из каталога, вызвав локальный файл `@@ Target-Csv-Generater.sql ', как в примере, и Позвольте мне знать, если это помогает? SQLDeveloper должно быть в порядке. Конечно, мы можем поболтать, я пробуду несколько часов. - person alexgibbs; 07.09.2017
comment
Спасибо, Алекс. На самом деле в моей предыдущей попытке я попытался поместить @@ Target-Csv-Generator.sql также в рабочий каталог, но все еще не генерировал файл excel. Поскольку я использую рабочий каталог, по этой причине он создает файл Loop-Flattener.sql, но не файл Excel в этом каталоге. Я думаю, что где-то делаю небольшую ошибку, но не могу ее идентифицировать. Могу ли я поделиться своим кодом? Но я не знаю, как мне поделиться? Изучив код, вам может быть легко идентифицировать ошибку. - person Andrew; 07.09.2017
comment
Спасибо, @Andrew, конечно, ты можешь опубликовать код, и я могу посмотреть. Вы можете обновить вопрос, добавив в него пример EMPLYOEE_MARKET данных и текущий код буферизации, и мы сможем продолжить. Было бы хорошо проверить, работает ли этот одноразовый пример ABC в его нынешнем виде и для вас. Спасибо - person alexgibbs; 08.09.2017
comment
Спасибо, Алекс. Я отредактировал свой вопрос и упомянул пример, который я пытаюсь найти в рабочем каталоге. На самом деле это не создание файла Excel. Пример, который я пробую, отличается от данных employee_market. Я также предоставил данные результатов выборочного запроса из @@ Target-Csv-Generator.sql. Я думаю, что где-то есть небольшая ошибка, которая не создает файл Excel. И да, в предыдущем примере, который вы упомянули, используя цикл for с использованием PL / SQL, он работает и генерирует файл Excel для того же запроса. - person Andrew; 10.09.2017
comment
Спасибо, @Andrew Ok, изучаю это сейчас. Я обновлю свой пост, добавив что-нибудь, что проверено на работоспособность, но, на первый взгляд, я бы с подозрением отнесся к SPOOL H:\TEST_REPORT\REPORT_FOR_&&TARGET..csv;. SQLPlus работает с путями относительно того, где был запущен сам SQLPlus, или относительно текущего скрипта (@ vs @@). Таким образом, это может быть попытка создать незаконный файл Windows. - person alexgibbs; 10.09.2017
comment
Хорошо, @Andrew, я выбросил исходные примеры и добавил решение, которое работает с вашими конкретными таблицами / запросами. Для простоты требуется, чтобы вы помещали сценарии в тот же каталог, где вы запускаете SQLPlus. Можете ли вы попробовать и сообщить мне, как это происходит? Спасибо - person alexgibbs; 10.09.2017
comment
Спасибо, Алекс, теперь он отлично работает. Я думаю, что единственное, чего не хватало в предыдущем коде, это вызов @@ Loop-Flattener.sql; в Generate-And-Run.sql. Но теперь это работает Спасибо за ваше драгоценное время и помощь. Это действительно очень помогло вместо создания каталога в oracle и других вещей, которые я не могу сделать из-за проблемы с безопасностью со стороны клиента. - person Andrew; 11.09.2017
comment
Приятно слышать @Andrew! И не беспокойтесь - я понимаю, что использование UTL_FILE иногда может быть проблемой. Если вы считаете, что на ваш вопрос был дан ответ, подумайте о том, чтобы принять ответ. Если возникнут другие вопросы, просто дайте мне знать. Спасибо - person alexgibbs; 11.09.2017

Вы не можете вызывать спул в блоке pl / sql. Спул - это команда sqlplus, а не pl / sql. Переместите оператор перед оператором DECLARE.

person OldProgrammer    schedule 03.09.2017