Oracle PL/SQL: дамп результата запроса в файл

Я работаю над хранимой процедурой pl sql. Мне нужно сделать выбор, использовать курсор и для каждой записи построить строку, используя значения. В конце мне нужно записать это в файл. Я пытаюсь использовать dbms_output.put_line("toto"), но размер буфера слишком мал, потому что у меня около 14 миллионов строк. Я вызываю свою процедуру из юниксового ksh. Я думаю о чем-то вроде использования «spool on» (на стороне ksh), чтобы сбросить результат моей процедуры, но я не знаю, как это сделать (если это возможно)

У кого-нибудь есть идеи?


person CC.    schedule 31.03.2010    source источник
comment
Из любопытства, вы пробовали мое решение?   -  person Peter Lang    schedule 31.03.2010
comment
Я уже ответил. Я не могу позволить себе делать больше, чем один раз запрос. Ваше решение (аналитическая функция) требует, чтобы запрос выполнялся более одного раза. Другое решение не работает ни потому, что мне нужно иметь значение поля из предыдущей итерации.   -  person CC.    schedule 31.03.2010
comment
Почему вам нужно выполнять запрос более одного раза с помощью аналитических функций? Вы читали мой последний комментарий?   -  person Peter Lang    schedule 31.03.2010
comment
Может быть, я был неправ. Я попытаюсь выполнить ваше решение.   -  person CC.    schedule 31.03.2010
comment
Я только что попробовал ваше решение, и оно даже лучше, чем то, которое я выбрал в первый раз. Сначала я неправильно понял, но теперь я понял. Большое спасибо.   -  person CC.    schedule 01.04.2010


Ответы (4)


Если это действительно необходимо, я бы не использовал процедуру.

Если вы вызываете скрипт с помощью SQLPlus, просто поместите следующее в свой test.sql (SET взяты из SQLПлюс часто задаваемые вопросы для удаления шума):

SET ECHO OFF
SET NEWPAGE 0
SET SPACE 0
SET PAGESIZE 0
SET FEEDBACK OFF
SET HEADING OFF
SET TRIMSPOOL ON
SET TAB OFF

Select owner || ';' || object_name
From all_objects;

QUIT

и перенаправить вывод в файл (test.txt):

sqlplus user/passwd@instance @ test.sql > test.txt

Если вам действительно нужно что-то делать на PL/SQL, подумайте о том, чтобы поместить это в функцию и вызвать ее для каждой записи:

Create Or Replace Function calculate_my_row( in_some_data In Varchar2 )
  Return Varchar2
As
Begin
  Return in_some_data || 'something-complicated';
End calculate_my_row;

Вызов:

Select owner || ';' || calculate_my_row( object_name )
From all_objects;

Производительность может пострадать, но она должна работать. Убедитесь, что то, что вы пытаетесь сделать, не может быть сделано в чистом SQL.


Читая ваш комментарий, я думаю, что аналитическая функция Lag что вам нужно.

В этом примере добавляется *, если значение val изменилось:

With x As (
      Select 1 id, 'A' val FROM dual
Union Select 2 id, 'A' val FROM dual
Union Select 3 id, 'B' val FROM dual
Union Select 4 id, 'B' val FROM dual
)
--# End of test-data
Select
  id,
  val,
  Case When ( val <> prev_val Or prev_val Is Null ) Then '*' End As changed
From (
  Select id, val, Lag( val ) Over ( Order By id ) As prev_val
  From x
)
Order By id

Возвращает

        ID V C
---------- - -
         1 A *
         2 A  
         3 B *
         4 B  
person Peter Lang    schedule 31.03.2010
comment
Это также не работает, потому что проблема в том, что мне нужно сделать некоторые вещи для каждой строки, поэтому я сделал курсор, а внутри я делаю свои вещи для каждой строки. - person CC.; 31.03.2010
comment
Пожалуйста, смотрите мой обновленный ответ. Что вы пытаетесь сделать, чего нельзя сделать в чистом SQL? - person Peter Lang; 31.03.2010
comment
Неплохое это решение, но... :) Обработка, которую я выполняю для каждой строки, такова: если предыдущее значение поля отличается от текущего значения, я что-то объединяю, иначе ничего не делаю. Таким образом, с помощью курсора это работает, но я не могу / не знаю, как вывести результат. - person CC.; 31.03.2010
comment
Интересное решение, но у меня 14 миллионов строк, и я пытаюсь что-то сделать в разумные сроки. Я не могу позволить себе 4 раза выбирать. - person CC.; 31.03.2010
comment
Не уверен, что вы имеете в виду? Мои 4 выбора предназначены только для предоставления некоторых тестовых данных. Удалите часть перед End of test-data и выберите из таблицы. Производительность на самом деле должна быть намного лучше, чем с вашим текущим решением. - person Peter Lang; 31.03.2010

Если каждая строка вашего вывода является результатом операции над одной строкой в ​​таблице, то хранимая функция в сочетании с ответом Питера Ланга может сделать то, что вам нужно.

create function create_string(p_foobar foobar%rowtype) return varchar2 as
begin
  do_some_stuff(p_foobar);
  return p_foobar.foo || ';' ||p_foobar.bar;
end;
/

Если это сложнее, возможно, вы можете использовать конвейерную табличную функцию.

create type varchar_array
    as table of varchar2(2000)
/

create function output_pipelined return varchar_array PIPELINED as
  v_line varchar2(2000);
begin
  for r_foobar in (select * from foobar)
  loop
    v_line := create_string(r_foobar);
    pipe row(v_line);
  end loop;
  return;
end;
/ 

select * from TABLE(output_pipelined);  
person Erich Kitzmueller    schedule 31.03.2010
comment
Я пробую это решение, но поскольку у меня огромное количество данных, могу ли я его использовать? v_line будет иметь более 2000 символов? Он все еще работает? Или в v_line есть информация только об одной строке? - person CC.; 31.03.2010

utl_file — ваш друг http://www.adp-gmbh.ch/ora/plsql/utl_file.html Но он записывает данные в файловую систему на сервере, поэтому для этого вам, вероятно, понадобится помощь вашего администратора баз данных.

person Rob van Laarhoven    schedule 31.03.2010
comment
Я видел utl_file, но не могу его использовать, потому что у меня нет прав. - person CC.; 31.03.2010