четверг, 27 декабря 2012 г.

Объект DIRECTORY в ORACLE

Объект базы данных DIRECTORY - это ссылка на каталог сервера, на котором работает инстанс Oracle. Он нужен для пакета UTL_FILE, работы утилит impdp/expdp, при использовании полей типа BFILE в таблицах, а также при создании внешних таблиц (external tables).
Вот что можно делать с объектом DIRECTORY:


Пара замечаний:
  • При создании директории ORACLE не проверяет её наличие и доступность, поэтому о создании каталога на диске и предоставлении прав на него пользователю-владельцу инстанса надо позаботиться заранее. Если этого не сделать, то при попытке обращения получим ошибку.
  • При удалении директории всё её содержимое остаётся в файловой системе.
  • Надо с осторожностью раздавать пользователям привилегию CREATE ANY DIRECTORY, так как у них появится возможность изменять любые файлы ОС, к которым есть доступ у пользователя-владельца инстанса

Регистрация приложения OEBS

Источники:

http://onlineappsdba.blogspot.com/2007/10/creating-custom-application-in-oracle.html
http://apps-oracle.ru/registration_application/
http://www.appshosting.com/pub_doc/custom_top.html

Кратко

  1. Создать структуру каталогов
  2. Изменить файл (по умолчанию defaults.env) настроек переменных окружения для сервера форм. Его имя хранится в переменной окружения envFile в файле appsweb.cfg, имя и путь к которому в свою очередь хранятся в переменной окружения  FORMS_WEB_CONFIG_FILE, добавив строку с установкой значения переменной окружения <префикс приложения (ЗАГЛАВНЫМИ)>_TOP. Тем самым будет определён каталог, в котором сервер Oracle Forms сможет найти файлы приложения
  3. В файл $APPL_TOP/custom<имя инстанса>.env следует добавить инициализацию тех же переменных с последующим их экспортом (это необходимо для выполнения системных процедур и вызова параллельных запросов) и проверить наличие вызова это файла из $APPL_TOP/APPS<имя инстанса>.env. При наличии в составе приложения исполняемых операционной системой программ также следует добавлять <префикс приложения (ЗАГЛАВНЫМИ)>_TOP/bin к переменной окружения PATH (если используется)
  4. Остановить менеджер параллельных программ (concurrent manager)
    $ADMIN_SCRIPTS_HOME/adcmctl.sh stop apps/apps
  5. Выполнить файл, замещающий APPLSYS.env
    . / $APPL_TOP/APPS<имя инстанса>.env
  6. Перезапустить concurrent manager
    $ADMIN_SCRIPTS_HOME/adcmctl.sh start apps/apps
  7. Войдите в систему с полномочиями Разработчик приложений (Application Developer) и зарегистрируйте приложение
  8. Войдите в систему с полномочиями System Administrator и добавьте приложение в группу данных (раздел меню «Security : ORACLE», пункт «Группа данных»)

Подробнее

Custom Applications are required if you are creating new forms, reports, etc.   
This allows you to segregate your custom written files from the standard seeded functionality that
Oracle Applications provide.     
Customizations can therefore be preserved when applying patches or upgrades to your environment. 
1)  Make the directory structure for your custom application files.
               cd $APPL_TOP
               mkdir fz
               mkdir fz/11.5.0
               mkdir fz/11.5.0/admin
               mkdir fz/11.5.0/admin/sql
               mkdir fz/11.5.0/admin/odf
               mkdir fz/11.5.0/sql
               mkdir fz/11.5.0/bin
               mkdir fz/11.5.0/reports
               mkdir fz/11.5.0/reports/US
               mkdir fz/11.5.0/forms
               mkdir fz/11.5.0/forms/US 
               mkdir fz/11.5.0/$APPLLIB
               mkdir fz/11.5.0/$APPLOUT
               mkdir fz/11.5.0/$APPLLOG 
2)  Add the custom module into the environment
Apply ADX.E.1 and add the entry to topfile.txt as a standard product top entry .   
Customised environment variables can be added to AutoConfig by using the filename specificed by s_custom_file, 
which is then called from the APPSORA.env file. 
If using Forms Listener Servlet, you may also need to add $CUSTOM_TOP to formsservlet.ini in
$APACHE_TOP/Jserv/etc 
3)  Create new tablespace for database objects
     create tablespace FZ datafile '/u01/oracle/visdata/fz.dbf' size 10M default storage(initial 10k next 10k)
4)  Create schema
               create user fz identified by fz
                               default tablespace fz
                               temporary tablespace temp
                               quota unlimited on fz
                               quota unlimited on temp;
               grant connect, resource to fz;
5)  Register your Oracle Schema. 
     Login to Applications with System Administrator responsibility
     Navigate to Application-->Register
               Application = FZ Custom
               Short Name  = FZ
               Basepath    = FZ_TOP
               Description = FZ Custom Application
6)  Register Oracle User
     Naviate to Security-->Oracle-->Register
               Database User Name = FZ
               Password           = FZ
               Privilege          = Enabled
               Install Group      = 0
               Description        = FZ Custom Application User
7)  Add Application to a Data Group
     Navigate to Security-->Oracle-->DataGroup
               Data Group  = FZGroup
               Description = FZ Custom Data Group
      Click on "Copy Applications from" and pick Standard data Group, then add the following entry.
               Application = FZ Custom
               Oracle ID   = APPS
               Description = FZ Custom Application
8)  Create custom request group
     This will act as a placeholder for any custom reports we wish to make available for the Custom Responsibility 
      Navigate to Security-->responsbility-->Request
               Group       = FZ Request Group
               Application = FZ Custom
               Code        = FZ
               Description = FZ Custom Requests
       We will not define any requests to add to the group at this stage, but you can add some now if required.
9)  Create custom menu
      This will act as a placeholder for any menu items we wish to make available for the Custom Responsibility. 
      We will create two menus, one for Core Applications and one for Self Service.
       Navigate to Application-->Menu
               Menu           = FZ_CUSTOM_MENU
               User Menu Name = FZ Custom Application
               Menu Type      = <leave blank>
               Description    = FZ Custom Application Menu
               Seq         = 100
               Prompt      = View Requests
               Submenu     = <leave blank>
               Function    = View All Concurrent Requests
               Description = View Requests
               Seq         = 110
               Prompt      = Run Requests
               Submenu     = <leave blank>
               Function    = Requests: Submit
               Description = Submit Requests
               Menu           = FZ_CUSTOM_MENU_SSWA
               User Menu Name = FZ Custom Application SSWA
               Menu Type      = <leave blank>
               Description    = FZ Custom Application Menu for SSWA 
10)  Create new responsibility.   One for Core Applications and One for Self Service (SSWA)
       Navigate to Security-->Responsibility-->Define
               Responsibility Name       = FZ Custom
               Application               = FZ Custom
               Responsibility Key        = FZCUSTOM
               Description               = FZ Custom Responsibility
               Available From            = Oracle Applications
               Data Group Name           = fzGroup
               Data Group Application    = FZ Custom
               Menu                      = FZ Custom Application
               Request Group Name        = FZ Request Group
 
               Responsibility Name       = FZ Custom SSWA
               Application               = FZ Custom
               Responsibility Key        = FZCUSTOMSSWA
               Description               = FZ Custom Responsibility SSWA
               Available From            = Oracle Self Service Web Applications
               Data Group Name           = fzGroup
               Data Group Application    = FZ Custom
               Menu                      = FZ Custom Application SSWA
               Request Group Name        = FZ Request Group
11)  Add responsibility to user
       Navigate to Security-->User-->Define
       Add FZ Custom responsibility to users as required.
12)  Other considerations
       You are now ready to create your database Objects, custom Reports, Forms, Packages, etc
Create the source code files in the FZ_TOP directory appropriate for the type of object.   For example forms
would be located in $FZ_TOP/forms/US or package source code in $FZ_TOP/admin/sql for example.
Database Objects, such as tables, indexes and sequences should be created in the FZ schema, then you need to 
               a) Grant all privilege from each custom data object to the APPS schema.
                               For example :  logged in as FZ user
                                              grant all privileges on myTable to apps;
               b) Create a synonym in APPS for each custom data object
                               For example :  logged in as APPS user
                                              create synonym myTable for fz.myTable;
Other database objects, such as views and packages should be created directly in the APPS schema.


понедельник, 17 декабря 2012 г.

Регистрация формы в ОЕБС

Для регистрации формы, разработанной в 6 версии Oracle Forms используем:


f60gen module=<FORM_NAME> userid=APPS/apps Module_Type=FORM Output_File=$<PRODUCT>_TOP/forms/US/<FORM_NAME>.fmx


Для регистрации формы, разработанной в 10 версии Oracle Forms используем:

frmcmp_batch module=$AU_TOP/forms/RU/XX_CITY.fmb userid=apps/apps module_type=FORM Compile_All=YES output_file=$AU_TOP/forms/RU/XX_CITY.fmx

четверг, 6 декабря 2012 г.

Трассировка сессии

Трассировка сессии Oracle помогает найти проблемные запросы и понять в чем именно причина.

Что именно будет записываться в трассировочный файл, определяется номером события (event).
Стандартный номер события 10046. Именно такой уровень устанавливается при выполнении команды1 alter session set sql_trace=true;


Список данных событий и для чего они предназначены можно посмотреть здесь EventReference



Событие трассировки 10046 / Trace event 10046

Включить трассировку в текущей сессии1 alter session set events '10046 trace name context forever, level 1';


выключить трассировку в текущей сессии1 alter session set events '10046 trace name context off';


Уровни:
0 – трассировка отключена
1 – стандартная трассировка
4 – добавлены значения связываемых (binds) переменных
8 – добавлены события ожидания (waits)
12 – связываемые переменные + события ожидания

Для включения трассировки в другой сессии можно воспользоваться командой1 sys.dbms_system.set_ev(sid, serial#, 10046, 12, '');


Путь к директории, где появится файл трассировки1 select value from v$parameter where name = 'user_dump_dest';


Задать имя для trace файла1 alter session set tracefile_identifier = 'mytrace1';




Понимание трасировочного файла


Выполняем следующий код, чтобы создать trace файл:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 SET SERVEROUTPUT ON
alter session set tracefile_identifier = 'mytrace2'
/
alter session set events '10046 trace name context forever, level 12'
/
declare
l_row_num number;
l_owner varchar2(10) := 'SYS';
begin
select count(1) into l_row_num from all_tables t where t.owner = l_owner;
dbms_output.put_line('num='||l_row_num);
end;
/
alter session set events '10046 trace name context forever, level 0'
/


Заголовок файла – содержит информацию об инстансе и сессии для которой создан1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 Trace file .../"instance_name"_ora_12591_mytrace2.trc
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
ORACLE_HOME = ...
System name: ...
Node name: ...
Release: ...
Version: ...
Machine: ...
Instance name: "instance_name"
Redo thread mounted by this instance: 1
Oracle process number: 545
Unix process pid: 12591, image: ...

*** 2012-09-19 12:07:49.268
*** SESSION ID:(669.6321) 2012-09-19 12:07:49.268
*** CLIENT ID:() 2012-09-19 12:07:49.268
*** SERVICE NAME:(...) 2012-09-19 12:07:49.268
*** MODULE NAME:(PL/SQL Developer) 2012-09-19 12:07:49.268
*** ACTION NAME:(Command Window - New) 2012-09-19 12:07:49.268


Разбор курсора1
2
3 PARSING IN CURSOR #11529215044981500944 len=54 dep=1 uid=44 oct=3 lid=44 tim=10192202222475 hv=1751201178 ad='c0000005d60dcaf0' sqlid='1f79yzdn62dcu'
SELECT COUNT(1) FROM ALL_TABLES T WHERE T.OWNER = :B1
END OF STMT


cинтаксис1
2
3 PARSING IN CURSOR #[CURSOR] len=X dep=X uid=X oct=X lid=X tim=X hv=X ad='X' sqlid='X'
[statement]
END OF STMT

[CURSOR] – номер курсора
len – длина SQL запроса
dep – рекурсивная глубина SQL запроса
uid – id пользователя (user) под которым был разобран запрос 1 select * from all_users where user_id = :uid;

oct – ID команды oracle. Можно увидеть в V$SQL.COMMAND_TYPE и V$SESSION.COMMAND
lid – ID схемы в которой был разобран запрос. Может отличаться от uid
tim – timestamp, в микросекундах
hv – hash значение, V$SQL.HASH_VALUE
ad – адрес. V$SQL.ADDRESS, V$SQLTEXT.ADDRESS
sqlid – ID запроса, V$SQL.SQL_ID

Основные операции1
2
3 PARSE #11529215044981500944:c=0,e=370,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=1,plh=0,tim=10192202222474
EXEC #11529215044981500944:c=270000,e=276923,p=0,cr=3,cu=0,mis=1,r=0,dep=1,og=1,plh=242196440,tim=10192202499569
FETCH #11529215044981500944:c=840000,e=1466871,p=2776,cr=71124,cu=0,mis=0,r=1,dep=1,og=1,plh=242196440,tim=10192203966668


PARSE – разбор курсора, EXEC – выполнение курсора, FETCH – получение данных
cинтаксис1
2
3 PARSE #[CURSOR]:c=X,e=X,p=X,cr=X,cu=X,mis=X,r=X,dep=X,og=X,plh=X,tim=X
EXEC #[CURSOR]:c=X,e=X,p=X,cr=X,cu=X,mis=X,r=X,dep=X,og=X,plh=X,tim=X
FETCH #[CURSOR]:c=X,e=X,p=X,cr=X,cu=X,mis=X,r=X,dep=X,og=X,plh=X,tim=X

[CURSOR] – номер курсора
c – время в микросекундах затраченное процессором
e – общее затраченное время в микросекундах
p – число физических чтений (physical reads)
cr – количество блоков полученных в режиме согласованного чтения (retrieved for CR reads)
cu – количество блоков полученных в текущем режиме (retrieved in current mode)
mis – отсутствие курсора в кеше, выполняется hard parse
r – количество возвращаемых строк
dep – рекурсивная глубина запроса
og – Цель оптимизатора: 1=All_Rows, 2=First_Rows, 3=Rule, 4=Choose
plh – Hash значение для выполняемого плана. V$SQL_PLAN.PLAN_HASH_VALUE
tim – timestamp, в микросекундах

Связываемые переменные / binds1
2
3
4
5
6 BINDS #11529215044981500944:
Bind#0
oacdty=01 mxl=32(10) mxlc=00 mal=00 scl=00 pre=00
oacflg=13 fl2=206001 frm=01 csi=171 siz=32 off=0
kxsbbbfp=9fffffffbf3b37b8 bln=32 avl=03 flg=09
value="SYS"

[CURSOR] – номер курсора
bind#N – номер переменной
oacdty – тип данных
mxl- maximum length of the bind variable value (private maximum length in parentheses)
mxlc – ?
mal – длина массива
scl – масштаб (scale)
pre – точность (precision)
oacflg – special flag indicating bind options
fl2 – second part of oacflg
frm – ?
csi – идентификатор кодировки
siz – объем выделяемой памяти
off – offset into the chunk of the bind buffer
kxsbbbfp – адрес переменной
bln – длина буфера для переменной
avl – актуальная длина переменной
flg – статус переменной
value- значение переменной

Ожидания / wait1
2 WAIT #11529215044981500944: nam='Disk file operations I/O' ela= 285 FileOperation=2 fileno=4 filetype=2 obj#=397424 tim=10192202526355
WAIT #11529215044981500944: nam='db file sequential read' ela= 583 file#=4 block#=7927 blocks=1 obj#=397424 tim=10192202526996

[CURSOR] – номер курсора
nam- тип ожидания
ela – затраченное время в микросекундах
obj#- номер объекта
tim – timestamp, в микросекундах

Остальные параметры зависят от типа ожидания. Увидеть данные параметры можно с помощью запроса:1 select * from v$event_name where name = :waitname;


План выполнения1
2
3
4
5
6
7
8 STAT #11529215044981500944 id=1 cnt=1 pid=0 pos=1 obj=0 op='SORT AGGREGATE (cr=71124 pr=2776 pw=0 time=1466915 us)'
STAT #11529215044981500944 id=2 cnt=1047 pid=1 pos=1 obj=0 op='FILTER (cr=71124 pr=2776 pw=0 time=1123290 us)'
STAT #11529215044981500944 id=3 cnt=1047 pid=2 pos=1 obj=0 op='NESTED LOOPS OUTER (cr=68261 pr=2735 pw=0 time=1080842 us cost=3024 size=14145 card=115)'
STAT #11529215044981500944 id=4 cnt=1047 pid=3 pos=1 obj=0 op='HASH JOIN RIGHT OUTER (cr=64291 pr=2289 pw=0 time=954642 us cost=2820 size=11322 card=102)'
...
STAT #11529215044981500944 id=9 cnt=28 pid=8 pos=1 obj=16 op='TABLE ACCESS FULL TS$ (cr=33 pr=0 pw=0 time=1609 us cost=8 size=84 card=28)'
STAT #11529215044981500944 id=10 cnt=1047 pid=8 pos=2 obj=0 op='NESTED LOOPS (cr=62544 pr=2252 pw=0 time=561698 us cost=2620 size=8976 card=102)'
...

[CURSOR] – номер курсора
id – номер строки плана
cnt – количество обработанных строк
pid – идентификатор родителя
pos – позиция относительно родителя
obj – ID объекта. ALL_OBJECTS.OBJECT_ID и V$SQL_PLAN.OBJECT#.
op – операция
cr – согласованное чтение (Consistent read)
pr – физическое чтение (Physical reads)
pw – физическая запись (Physical writes)
time – timestamp, в микросекундах
cost – оценка выполнения запроса (CBO)
size – объем данных в байтах
card – число возвращаемых строк

Дополнительно можно почитать ноту Interpreting Raw SQL_TRACE output [ID 39817.1]

среда, 5 декабря 2012 г.

API добавления полномочия для пользователя

С помощью данного API можно добавить полномочие пользователю1

 begin
-- Call the procedure
fnd_user_pkg.addresp(username => :username,
resp_app => :resp_app,
resp_key => :resp_key,
security_group => :security_group, -- в основном 'STANDARD'
description => :description, -- любой коммент
start_date => :start_date,
end_date => :end_date);
commit;
dbms_output.put_line('Responsibility Added Successfully');
exception
when others then
dbms_output.put_line(' Responsibility is not added due to '
|| substr(SQLERRM, 1, 100));
rollback;
end;



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

declare
l_user_name varchar2(100) := 'USER_NAME';
begin
dbms_output.put_line('BEGIN');
-- цикл по списку полномочий пользователя
for i in (select 'fnd_user_pkg.addresp('''||u.user_name||''', '''
|| a.application_short_name ||''', '''
|| r.responsibility_key ||''', '''
|| 'STANDARD' ||''', '''
|| 'Add by script' ||''', '
|| 'sysdate' ||', '
|| 'null' ||');'
as script
, r.responsibility_name
from fnd_user u
,fnd_user_resp_groups g
,fnd_application_vl a
,fnd_responsibility_vl r
where g.user_id(+) = u.user_id
and g.responsibility_application_id = a.application_id
and a.application_id = r.application_id
and g.responsibility_id = r.responsibility_id
AND u.user_name = l_user_name
)
loop
dbms_output.put_line(' dbms_output.put_line('''||i.responsibility_name||''');');
dbms_output.put_line(' '||i.script);
dbms_output.put_line('');
end loop;
dbms_output.put_line(' commit;');
dbms_output.put_line(' dbms_output.put_line('''');');
dbms_output.put_line(' dbms_output.put_line(''Responsibility Added Successfully'');');
dbms_output.put_line('EXCEPTION');
dbms_output.put_line(' when others then');
dbms_output.put_line(' dbms_output.put_line('' Responsibility is not added due to '' || substr(SQLERRM, 1, 100));');
dbms_output.put_line(' rollback;');
dbms_output.put_line('END;');
end;

вторник, 27 ноября 2012 г.

О соединении данных столбца в одну строку с помощью SQL-запроса

Постановка задачи: в некоей таблице имеется столбец с данными. Необходимо эти данные склеить в строку с помощью одного SQL-запроса.

Часть I. Аналитика и иерархия.

Простой способ решения задачи подсказал Т.Кайт в статье On Ignoring, Locking, and Parsing. Этот способ основывается на использовании аналитических функций и функции SYS_CONNECT_BY_PATH для иерархических запросов и применим начиная с Oracle9i Database Release 1. Идея заключается в следующем.
  1. Выбираемые данные необходимо разделить на подгруппы, для которых будут склеиваться строки и в каждой подгруппе пронумеровать элементы в порядке их склеивания.
      select
        deptno,
        ename,
        row_number() over (partition by deptno order by ename) rn
      from emp
  2. С помощью иерархического запроса все данные подгруппы соединяются в одну ветку дерева. Для каждого узла с помощью функции SYS_CONNECT_BY_PATH вычисляется строка со всеми предшествующими значениями поля, разделенными заданным разделителем.
    select
      deptno,
      sys_connect_by_path(ename, ' ' ) scbp
    from
      (select
         deptno,
         ename,
         row_number() over (partition by deptno order by ename) rn
       from emp
      )
    start with rn = 1
    connect by prior rn = rn-1
    and prior deptno = deptno
  3. Далее остается сгруппировать полученные данные по идентификатору подгруппы и выбрать для каждой значение строки максимальной длинны.
    select
      deptno,
      max(sys_connect_by_path(ename, ' ' )) scbp
    from
      (select
         deptno,
         ename,
         row_number() over (partition by deptno order by ename) rn
       from emp
      )
    start with rn = 1
    connect by prior rn = rn-1
    and prior deptno = deptno
    group by deptno
    order by deptno
В результате получаем список сотрудников по отделам.
   DEPTNO         SCBP
---------         ----------------------------------
       10         CLARK KING MILLER
       20         ADAMS FORD JONES SCOTT ...
       30         ALLEN BLAKE JAMES MARTIN ...
Этот способ прост и удобен, но имеет один недостаток. Функция SYS_CONNECT_BY_PATH работает с переменными VARCHAR2, которые, как известно, ограничиваются размером 4000 символов. При большом объеме склеиваемых данных, неизбежно возникает ошибка ORA-01489: result of string concatenation is too long. Эту проблему решает второй способ решения задачи.

Часть II. XML и CLOB.

Второй вариант предусматривает использование аггрегатной функции XMLAGG для получения склеенной строки в виде XML-объекта, который может быть преобразован в CLOB.
select
  deptno,
  XMLAGG(XMLELEMENT("node", ename)).getCLOBVal() scbp
from emp
group by deptno
Для упорядочивания элементов в склеиваемой строке функции XMLAGG можно добавить сортировку.
select
  deptno,
  XMLAGG(XMLELEMENT("node", ename) order by ename).getCLOBVal() scbp
from emp
group by deptno
А если возникнет необходимость отсортировать полученные склеенные строки, можно воспользоваться преобразованием типов cast.
select
  deptno,
  XMLAGG(XMLELEMENT("node", ename) order by ename).getCLOBVal() scbp
from emp
group by deptno
order by cast( substr(scbp, 1, 4000) as varchar2(4000))
В результате получится следующее:
   DEPTNO         SCBP
---------         ----------------------------------
       20         <node>ADAMS</node><node>FORD</node> ...
       30         <node>ALLEN</node><node>BLAKE</node> ...
       10         <node>CLARK</node><node>KING</node>
Недостаток данного способа – наличие тэгов, которые необходимо обрабатывать в зависимости от целей поставленной задачи. Хотя для случая, ставшего причиной поиска описанного решения, тэги оказались скорее плюсом.
Этот же метод можно применить и для более коротких строк, где не требуется использование CLOB-данных. XML-объект можно преобразовать в varchar2 с помощью функции getStringVal().
select
  deptno,
  XMLAGG(XMLELEMENT("node", ename) order by ename).getStringVal() scbp
from emp
group by deptno
order by scbp

среда, 14 ноября 2012 г.

Окно - Исходный формат отчета отличается от конечного

Итак, если создан отчет с шаблоном в формате RTF,  а вывод в виде Excel, и выпадает окошко с сообщением, что исходный формат отчета отличается от конечного, а нам это окошко надо убрать с глаз долой, тогда правим:

В регистре:
HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Excel\Security
новый параметр (если нету) с типом DWORD , называем ExtensionHardening - значение 0

вторник, 6 ноября 2012 г.

Использование Oracle SQL*Loader для загрузки данных в таблицы

Использование Oracle SQL*Loader для загрузки данных в таблицы

Данный минифак не претендует на полноту отражения всех особенностей работы с SQL*Loader, а служит для того, чтобы быстро войти в тему
SQL*Loader — специальная утилита Oracle сервера для загрузки данных в БД из локальных файлов с данными. Для того чтобы воспользоваться ее функционалом создадим несколько файлов, которые будем использлвать в работе, и положим их в папку C:\oracle\ora90\BIN\load (в общем случае):

  • data.dat или data.txt — собственно файл с данными. Пусть он будет представлять строки данных разделенных сиволом перевода строки.
  • load.ctl — контрольный файл — содержит инструкции по загрузке данных в БД, в нашем случае будет иметь вид:
    LOAD DATA -- Загружаем данные
    INFILE 'data.txt'  "str '\n'" -- из файла data.txt, разделитель строк str '\n' - символ перевода строки
    INTO TABLE load_data -- в таблицу load_data
    FIELDS terminated BY ',' OPTIONALLY ENCLOSED BY '"'
    (DATA char) -- название столбца и тип данных в таблице load_data
    То что мы не используем, но встречается часто: fields terminated by ‘,’ означает, что границы данных определены по символу «,», а optionally enclosed by ‘»‘ определяет, что данные могут содержать символ обрамления.
  • load.bat — пакетный файл (англ. batch file) выполняющий запуск sqlldr.exe имеет вид:
    SET nls_lang=russian_cis.ru8pc866 -- устанавливаем нужную кодировку
    sqlldr.exe userid=user_name/user_pass@test control=LOAD.ctl errors=100 bad=DATA.bad -- test — строка связи*, load.ctl — контрольный файл, data.bad — файл плохих записей
    Строка связи — это та строка, которая должна быть прописана в ORA Network Configuration File: D:\oracle\ora90\network\admin\tnsnames.ora (в общем случае). Errors=100 — количество допустимых ошибок (по умолчанию 50).
  • Далее находим нашу папку C:\oracle\ora90\BIN\load, находим файл load.bat, запускаем его и любуемся на результат:
    SELECT * FROM load_data;
    Пока все, пишите об ошибках и неточностях.
Пара полезных ссылок по теме:
Примечание:
Интересно, что при сохранении *.xslx в «.csv с разделителем запятой» разделителем на самом деле становится точка с запятой.

Разбор/парсинг значения поля (строки) по разделителям на строки

Источник:  http://plsqlbook.ru/category/question-answer/


Простой пример того, о чем речь:
SELECT regexp_substr(str, '[^#]+', 1, LEVEL)
  FROM (SELECT 'one#two#tree' str FROM dual)
CONNECT BY instr(str, '#', 1, LEVEL-1) > 0
напоминалка:
  • ‘[^#]+’ такая маска найдет все символы кроме решетки
  • instr(str, ‘#’, 1, LEVEL-1) > 0 поиск позиции разделителя начиная с первой позиции и, видимо, с LEVEL = 2 (возвратит 0 если позиция при заданных параметрах не найдена)
  • CONNECT BY условие подсказывает ораклу как долго продолжать цикл
Результат:
1 one
2 two
3 tree
 
 
Вариант 2
 
select 
   ltrim(rtrim(
    substr(s_element,
         instr(s_element,',',1,iter.pos)+1,
         instr(s_element,',',1,iter.pos+1)-
         instr(s_element,',',1,iter.pos)),',')) s_element,iter.pos
from 
     (select ','||s_in||',' s_element from dual) csv,
     (select rownum pos from ra_customer_trx_all) iter
where 
     iter.pos <= ((length(csv.s_element)-length(replace(csv.s_element,',')))/length(','))-1 

где  s_in  - исходная строка

пятница, 19 октября 2012 г.

Создание шаблонов в формате Excel

Этот пост о том как создавать отчеты, выводящиеся в Excel с использованием XML Publisher.

На проекте необходимо было создать отчет в Excel. Проблема состояла в том, что в шаблоне было около 100 столбцов - поэтому вариант с созданием шаблона в RTF и последующим его выводом в виде Excel отпала сразу. Вариант с преобразованием шаблона в формате Excel в книгу XML и последующим выводом тегов из пакета тоже отпал - из-за настройки базы и аппсов русские символы, генерируемые в пакете, в итоге выводились в виде кракозябок. Выход был найден.

1. Создается шаблон в  Excel. В поля, в которых хотим сделать вывод переменных пишем :PARAM_NAME:   - ОБЯЗАТЕЛЬНО с двух сторон двоеточия - точки входа и выхода.



2. Сохраняем документ в формате книги XML

3. Разделяем наш файл по строкам на неизменяемые части - шапка, подвал, и на изменяемые - те что будут выводиться в цикле и заполняться данными.

4. Создаем таблицу, в которой будем хранить уникальный идентификатор нашего отчета, уникальный идентификатор части отчета (шапки, подвала, изменяемой части), описание этой самой части и поле типа CLOB для хранения куска XML с этой самой частью.



Чтобы не возникло проблем с кодировкой, правим:
<?xml version="1.0" encoding="windows-1251"?> 

Чтобы не выдавало ошибок при генерированиии большого количества строк ( по умолчанию часть  ExpandedRowCount равна около 300 строк), правим:
<Table ss:ExpandedColumnCount="19" ss:ExpandedRowCount="65000" x:FullColumns="1"

5. В пакете производим вывод нужных частей

    /*  Сводный отчет */
  PROCEDURE SVODNIJ(P_ORG_ID NUMBER, P_YEAR VARCHAR2, P_TYPE VARCHAR2,  P_DATA_VALUE VARCHAR2, P_VARIANT VARCHAR2) IS
    body_  clob;
  BEGIN
 
    -- Вывод шапки отчета
    body_ := xx_utils.get_xml_body(145, 11);
    body_ := xx_utils.reps(':FILIAL:',GET_ORG_NAME(P_ORG_ID), body_);
    body_ := xx_utils.reps(':YEAR:', GET_YEAR(P_YEAR), body_);
    xx_utils.put_line(body_);


________________________________________

 function get_xml_body(p_report_id number, --ID отчета
                        p_body_id   number--ID строки отчета
                        ) return clob as
    xml_clob clob;
  begin
    select t.xml_body
      into xml_clob
      from xx_reports t
     where t.report_id = p_report_id
       and t.body_id = p_body_id;
 
    return xml_clob;
  exception
    when others then
      return null;
  end get_xml_body;

__________________________

 function reps(var in varchar2, --Что заменяется
                val in varchar2, --На что заменяется
                sou in clob --Источник замены
                ) return clob as
  begin
    --return replace(sou, var, convert(val, 'UTF8', 'CL8MSWIN1251'));
    return replace(sou, var, val);
  end;



_____________________________


Для вывода я создавала параллельную программу, с исполняемым файлом - процедурой из пакета. При отработке запроса в файле результатов формируется xml документ и ОЕБС автоматически открывает его в Excel, таким образом получая нужный нам вид отчета.