Очень интересный проект по внедрению Oracle E-Business Suite R12, на котором я трудился 938 дней, подошел к концу. Ухожу поддерживать отечественного производителя.
Для истории:
Для истории:
@echo off @echo --------------------------------------- @echo Sync Java sources from java JSVN to source SSVN @echo --------------------------------------- # защита от случайного запуска. Обязательно должны запускать с -refresh if "%1" == "refresh" ( # временный каталог для импорта if exist c:\svn_tmp ( <nul set /p strTemp=Cleaning a temp folder... rmdir c:\svn_tmp /s /q <nul set /p strTemp=done. echo. ) # импорт содержимого репозитария svn export https://JSVN-url/java_folder c:\svn_tmp # если что-то появилось в каталоге, начинаем экспорт if exist c:\svn_tmp\xxmy000( <nul set /p strTemp=Cleaning old revisions in SSVN... svn delete svn://SSVN-url/appscode/trunk/XXMY/XXMY000/java/src/oracle/apps/xxmy/xxmy000 -m "clean old rev" <nul set /p strTemp=done. echo. <nul set /p strTemp=Importing new revisions to SSVN... svn import c:\svn_tmp\xxmy000 svn://SSVN-url/appscode/trunk/XXMY/XXMY000/java/src/oracle/apps/xxmy/xxmy000 -m "actualize" <nul set /p strTemp=done. echo. <nul set /p strTemp=Cleaning a temp folder... rmdir c:\svn_tmp /s /q <nul set /p strTemp=done. ) else ( @echo --------!! Error during import ) ) else ( @echo !Error: Parameter 1 not found. Nothing done. ) pause
CausesVOImpl causeVO = getAm().getCausesVO1();
// первое выполнение
if (!causeVO.isPreparedForExecution()){
causeVO.setMaxFetchSize(999);
}
causeVO.executeEmptyRowSet();
causeVO.setWhereClause("CAUSE_NUMBER > :1 and GROUP_ID = :2");
causeVO.setWhereClauseParam(0, causeNumber);
causeVO.setWhereClauseParam(1, groupId);
causeVO.executeQuery();
// второе выполнение
CausesVOImpl causeVO = getAm().getCausesVO1();
if (!causeVO.isPreparedForExecution()){
causeVO.setMaxFetchSize(999);
}
causeVO.executeEmptyRowSet();
// causeVO.setWhereClause(null);
// causeVO.setWhereClauseParams(null);
causeVO.setWhereClause("GROUP_ID = :1");
causeVO.setWhereClauseParam(0, getEntityId());
try{
causeVO.executeQuery();
}catch (Exception e){
System.out.println(e.getMessage());
}
В приведенном примере ошибка возникнет при втором вызове executeQuery(). Как видим, setWhereClause и setWhereClauseParam не перекрывают ранее заданные значения.XMLNode xmlNode = (XMLNode)reportVO.writeXML(4, XMLInterface.XML_OPT_ALL_ROWS);2) Добавление доп.параметров в XML (параметры шапки)
XMLNode xmlNode = (XMLNode)am.invokeMethod("fillWithVODataset");
XMLDocument doc = xmlNode.getDocument();
Element elem = doc.createElement("ReportInfo");
Element elemPeriod = doc.createElement("SomeParameter");
Text startPeriodVal = doc.createTextNode((String)someBean.getValue(pageContext));
elemPeriod.appendChild(startPeriodVal);
elem.appendChild(elemPeriod);
XMLNode firstChild = (XMLNode)xmlNode.getFirstChild();
// xmlNode пуст, если VO был пуст
if (firstChild != null){
XMLNode parent = (XMLNode)firstChild.getParentNode();
parent.appendChild(elem);
}else{
// добавляем элемент в корень
xmlNode.appendChild(elem);
}
3) Натягиваем данные на существующий шаблон XDOselect lb.file_data from xdo_templates_b tmp, xdo_lobs lb where tmp.template_code = :1 and tmp.application_short_name = :2 and lb.application_short_name = tmp.application_short_name and lb.lob_code = tmp.data_source_code and lb.lob_type = 'TEMPLATE' and sysdate between tmp.start_date and nvl(tmp.end_date,sysdate)4) Формируем выходной поток с помощью класса oracle.apps.xdo.template.FOProcessor
<dataStructure> <group name="reportVORow" source="reportVORow"> <element name="ATTR1" value="ATTR1"/> <element name="ATTR2" value="ATTR2"/> ... <group name="ReportInfo" source="ReportInfo"> <element name="SomeParameter" value="SomeParameter"/> ...
:global.menu_to_appcore := 'ADVANCED_RECORD_HISTORY';
execute_trigger('menu_to_appcore');
Сохраняем файл, заливаем на сервер: frmcmp_batch module=FNDMENU.mmb userid=apps/apps output_file=$AU_TOP/resource/RU/FNDMENU.mmx compile_all=special module_type=menu ... - Inserting menu FNDMENU. - Inserting menu FILE. - Inserting menu EDIT. - Inserting menu VIEW. - Inserting menu FOLDER. - Inserting menu SPECIAL. - Inserting menu SPECIAL_B. - Inserting menu SPECIAL_C. - Inserting menu HELP. - Inserting menu QUERY. - Inserting menu DIAGNOSTICS. - Inserting menu TRACE_MENU. - Inserting menu LOGGING_MENU. - Inserting menu PROPERTIES_MENU. - Inserting menu CUSTOM_CODE_MENU. - Inserting menu CLEAR. - Inserting menu DUPLICATE. - Inserting menu PREFERENCES. - Inserting menu RECORD. - Ready.После перезахода в Forms увидим наш пункт меню:
XXFND999.event(event_name);- создаем кастомную библиотеку XXFND999.pll c обработчиком EVENT. Обработчик выполняет двойную функцию: создает пункт меню один раз и вызывает форму при активации одноименного триггера.
procedure event(p_event_name in varchar2) is l_item_label CONSTANT varchar2(100) := 'Расширенная история записи'; l_event_name varchar2(100); l_tgt_fn_app CONSTANT varchar2(200) := 'XXMY'; l_tgt_fn_name CONSTANT varchar2(300) := 'XXFND999_HISTORY_RECORD_ADV'; l_form_name CONSTANT varchar2(300) := l_tgt_fn_name; l_frm_path varchar2(5000); param_id paramlist; l_item_feature varchar2(150); l_created_by item; l_tmp varchar2(150); l_block varchar2(150); begin -- отменяем отработку функционала внутри формы if name_in('SYSTEM.CURRENT_FORM') = l_form_name then return; end if; l_block := name_in('SYSTEM.CURRENT_BLOCK'); -- проверка на существование блока if length(l_block) = 0 then return; end if; -- событие при создании экземпляра формы if p_event_name = 'WHEN-NEW-BLOCK-INSTANCE' then l_event_name := xx_form_custom.create_special(l_item_label,'LINE'); end if; /* кастомный метод для получения первой незанятой ячейки SPECIAL */ l_event_name := xx_form_custom.get_special(l_item_label); -- включение видимости и активация нового пункта xx_form_custom.activate_special(l_item_label); -- сохранение пункта меню xx_form_custom.save_menu(); -- если вызвали нашу форму if (p_event_name = l_event_name)then l_frm_path := fnd_navigate.formpath(l_tgt_fn_app, l_tgt_fn_name); -- проверяем наличие поля CREATED_BY в таблице с текущей записью l_created_by := find_item(name_in('SYSTEM.CURRENT_BLOCK')||'.CREATED_BY'); if not id_null(l_created_by) then -- проверяем наличие созданного списка параметров param_id := get_parameter_list('FND_FORM_ARGS'); if (not id_null(param_id)) then destroy_parameter_list(param_id); end if; -- создаем список параметров и добавляем информацию из служебных полей param_id := create_parameter_list('FND_FORM_ARGS'); add_parameter( param_id, 'CREATED_BY', TEXT_PARAMETER, name_in(name_in('SYSTEM.CURSOR_BLOCK')||'.CREATED_BY')); add_parameter( param_id, 'LAST_UPDATED_BY', TEXT_PARAMETER, name_in(name_in('SYSTEM.CURSOR_BLOCK')||'.LAST_UPDATED_BY')); add_parameter( param_id, 'CREATION_DATE', TEXT_PARAMETER,name_in(name_in('SYSTEM.CURSOR_BLOCK')||'.CREATION_DATE')); add_parameter( param_id, 'LAST_UPDATE_DATE', TEXT_PARAMETER, name_in(name_in('SYSTEM.CURSOR_BLOCK')||'.LAST_UPDATE_DATE')); -- открываем форму open_form ( formmodule_name => l_frm_path , activate_mode => ACTIVATE , session_mode => SESSION , data_mode => NO_SHARE_LIBRARY_DATA , paramlist_id => param_id ); end if; end if; end event;Этап 2: создание формы. Создаем Data Block, создаем триггер WHEN-NEW-BLOCK-INSTANCE и item USER_INFO, которому будем присваивать строку с данными о пользователе, разделенными через перевод строки. Создаем канву, бросаем туда item USER_INFO, ставим в свойствах Multiline=yes, Length=32000. Создаем несколько параметров, идентичных прописанным в кастомной библиотеке: CREATED_BY, LAST_UPDATED_BY, CREATION_DATE, LAST_UPDATE_DATE. Начинаем править код PL/SQL созданного блока данных и прописываем туда такое:
declare
l_create_id varchar2(50) := :PARAMETER.CREATED_BY;
l_update_id varchar2(50) := :PARAMETER.LAST_UPDATED_BY;
l_create_date varchar2(50) := :PARAMETER.CREATION_DATE;
l_update_date varchar2(50) := :PARAMETER.LAST_UPDATE_DATE;
begin
:XXFND361_TEST_V.CREATED_BY_FULLNAME := XXFND361_PKG.get_record_history(p_create_id => l_create_id,
p_update_id => l_update_id,
p_create_date => l_create_date,
p_update_date => l_update_date
);
XXFND999_PKG - обычный PL/SQL пакет:function get_record_history(p_create_id in varchar2, p_update_id in varchar2, p_create_date in varchar2, p_update_date in varchar2 ) return varchar2 is l_result_line varchar2(32000); l_create_person varchar2(150); l_create_org_id varchar2(150); l_create_job varchar2(150); l_create_contact varchar2(150); l_update_person varchar2(150); l_update_org_id varchar2(150); l_update_job varchar2(150); l_update_contact varchar2(150); l_is_person varchar2(1); l_create_organization_id number; l_update_organization_id number; l_create_id varchar2(150) := p_create_id; l_update_id varchar2(150) := p_update_id; l_create_date varchar2(150) := p_create_date; l_update_date varchar2(150) := p_update_date; begin if l_create_id is null then return ''; end if; select case when user_det.full_name is null then fnu.user_name else decode(regexp_substr(upper(user_det.full_name),'I'), null, user_det.full_name, fnu.user_name) || ' ' || user_det.employee_number end, decode(user_det.full_name, null, 'N', 'Y') into l_create_person, l_is_person from FND_USER fnu, per_all_people_f user_det where fnu.employee_id = user_det.person_id(+) and trunc(sysdate) between user_det.effective_start_date(+) and user_det.effective_end_date(+) and fnu.user_id = to_number(l_create_id); -- if l_is_person = 'Y' then begin select asg.organization_id into l_create_organization_id from per_all_people_f user_det, per_all_assignments_f asg, FND_USER fnu where user_det.person_id = asg.person_id and fnu.employee_id = user_det.person_id and trunc(sysdate) between user_det.effective_start_date and user_det.effective_end_date and trunc(sysdate) between asg.effective_start_date and asg.effective_end_date and fnu.user_id = to_number(l_create_id); exception when NO_DATA_FOUND then null; end; -- begin select j.name into l_create_job from per_all_people_f user_det, per_all_assignments_f asg, FND_USER fnu, per_jobs j where user_det.person_id = asg.person_id and fnu.employee_id = user_det.person_id and asg.job_id = j.job_id and trunc(sysdate) between user_det.effective_start_date and user_det.effective_end_date and trunc(sysdate) between asg.effective_start_date and asg.effective_end_date and trunc(sysdate) >= j.date_from and j.date_to is null and fnu.user_id = to_number(l_create_id) and rownum = 1; exception when NO_DATA_FOUND then null; end; -- begin select coalesce(user_det.email_address, fnu.Email_Address, ' ') || ' ' || user_det.work_telephone into l_create_contact from per_all_people_f user_det, per_all_assignments_f asg, FND_USER fnu where user_det.person_id = asg.person_id and fnu.employee_id = user_det.person_id and trunc(sysdate) between user_det.effective_start_date and user_det.effective_end_date and trunc(sysdate) between asg.effective_start_date and asg.effective_end_date and fnu.user_id = to_number(l_create_id); exception when NO_DATA_FOUND then null; end; end if; -------------------------- l_is_person := ''; -------------------------- select case when user_det.full_name is null then fnu.user_name else decode(regexp_substr(upper(user_det.full_name),'I'), null, user_det.full_name, fnu.user_name) || ' ' || user_det.employee_number end, decode(user_det.full_name, null, 'N', 'Y') into l_update_person, l_is_person from FND_USER fnu, per_all_people_f user_det where fnu.employee_id = user_det.person_id(+) and trunc(sysdate) between user_det.effective_start_date(+) and user_det.effective_end_date(+) and fnu.user_id = to_number(l_update_id); if l_is_person = 'Y' then begin select asg.organization_id into l_update_organization_id from per_all_people_f user_det, per_all_assignments_f asg, FND_USER fnu where user_det.person_id = asg.person_id and fnu.employee_id = user_det.person_id and trunc(sysdate) between user_det.effective_start_date and user_det.effective_end_date and trunc(sysdate) between asg.effective_start_date and asg.effective_end_date and fnu.user_id = to_number(l_update_id); exception when NO_DATA_FOUND then null; end; -- begin select j.name into l_update_job from per_all_people_f user_det, per_all_assignments_f asg, FND_USER fnu, per_jobs j where user_det.person_id = asg.person_id and fnu.employee_id = user_det.person_id and asg.job_id = j.job_id and trunc(sysdate) between user_det.effective_start_date and user_det.effective_end_date and trunc(sysdate) between asg.effective_start_date and asg.effective_end_date and trunc(sysdate) >= j.date_from and j.date_to is null and fnu.user_id = to_number(l_update_id); exception when NO_DATA_FOUND then null; end; -- begin select coalesce(user_det.email_address, fnu.Email_Address, ' ') || ' ' || user_det.work_telephone into l_update_contact from per_all_people_f user_det, per_all_assignments_f asg, FND_USER fnu where user_det.person_id = asg.person_id and fnu.employee_id = user_det.person_id and trunc(sysdate) between user_det.effective_start_date and user_det.effective_end_date and trunc(sysdate) between asg.effective_start_date and asg.effective_end_date and fnu.user_id = to_number(l_update_id); exception when NO_DATA_FOUND then null; end; end if; --------------- select decode(l_create_person, null, '', 'Создал запись ' || l_create_person || chr(10)) into l_create_person from dual; select decode(l_create_org_id, null, '', 'Структурное подразделение ' || l_create_org_id || chr(10)) into l_create_org_id from dual; select decode(l_create_job, null, '', 'Должность ' || l_create_job || chr(10)) into l_create_job from dual; if length(trim(l_create_contact)) > 0 then l_create_contact := 'Контакты ' || l_create_contact || chr(10); else l_create_contact := ''; end if; select decode(l_create_date, null, '', 'Дата создания записи ' || l_create_date || chr(10)) into l_create_date from dual; select decode(l_update_person, null, '', 'Изменил запись ' || l_update_person || chr(10)) into l_update_person from dual; select decode(l_update_org_id, null, '', 'Структурное подразделение ' || l_update_org_id || chr(10)) into l_update_org_id from dual; select decode(l_update_job, null, '', 'Должность ' || l_update_job || chr(10)) into l_update_job from dual; if length(trim(l_update_contact)) > 0 then l_update_contact := 'Контакты ' || l_update_contact || chr(10); else l_update_contact := ''; end if; select decode(l_update_date, null, '', 'Дата изменения записи ' || l_update_date) into l_update_date from dual; l_result_line := l_create_person || l_create_org_id || l_create_job || l_create_contact || l_create_date || chr(10) || l_update_person || l_update_org_id || l_update_job || l_update_contact || l_update_date; return l_result_line; exception when OTHERS then return 'Ошибка! p_create_id=' || l_create_id || ';' || 'l_update_id=' || l_update_id || ';' || 'l_create_date=' || l_create_date || ';' || 'l_update_date=' || l_update_date || 'error info: ' || sqlerrm; end get_record_history;Этап 3: создание и связывание функции, формы в Forms. После того, как всё это будет создано, установка производится следующим скриптом:
cp ./forms/XXFND999_HISTORY_RECORD_ADV.fmb $AU_TOP/forms/RU cp ./forms/XXFND999_HISTORY_RECORD_ADV.fmb $AU_TOP/forms/US cp ./resource/CUSTOM.pll $AU_TOP/resource/CUSTOM.pll cp ./resource/XXFND999_CUSTOM.pll $AU_TOP/resource/XXFND999_CUSTOM.pll cd $AU_TOP/forms/RU frmcmp_batch.sh module=$AU_TOP/forms/RU/XXFND999_HISTORY_RECORD_ADV.fmb userid=$APPSID module_type=form compile_all=yes output_file=$XX_TOP/forms/RU/XXFND999_HISTORY_RECORD_ADV.fmx cd $AU_TOP/forms/US frmcmp_batch.sh module=$AU_TOP/forms/US/XXFND999_HISTORY_RECORD_ADV.fmb userid=$APPSID module_type=form compile_all=yes output_file=$XX_TOP/forms/US/XXFND999_HISTORY_RECORD_ADV.fmx cd $AU_TOP/resource frmcmp_batch.sh module=$AU_TOP/resource/XXFND999_CUSTOM.pll userid=$APPSID module_type=library compile_all=yes output_file=$AU_TOP/resource/XXFND999_CUSTOM.plx frmcmp_batch.sh module=$AU_TOP/resource/CUSTOM.pll userid=$APPSID module_type=library compile_all=yes output_file=$AU_TOP/resource/CUSTOM.plxРезультат:
name_in(name_in('SYSTEM.CURSOR_BLOCK')||'.CREATED_BY'));
FRM-10056: Incorrect module type stored in the file. Неправильный параметр в sh-скрипте установки расширения. Внимание:frmcmp_batch.sh module=$AU_TOP/forms/US/XXFND999_HISTORY_RECORD_ADV.fmb userid=$APPSID module_type=form compile_all=yes output_file=$XX_TOP/forms/US/XXFND999_HISTORY_RECORD_ADV.fmx
FRM-91507: Internal Error: Unable to generate library. Ошибка в кастомной библиотекеCO:2. Работа канкарента
Serializable[] aserializable = { uploadId }; Class[] aclass = { uploadId.getClass() }; String requestId = (String)am.invokeMethod("sendConcurrentRequest", aserializable, aclass); am.getTransaction().commit();AM:
public void sendConcurrentRequest(Number uploadId) throws RequestSubmissionException { ConcurrentRequest cpRequest = new ConcurrentRequest(this.getOADBTransaction().getJdbcConnection()); Vector requestParameters = new Vector(1); requestParameters.add(uploadId.stringValue()); int requestId = cpRequest.submitRequest(UploadHistFactBean.APPLICATION_SHORT_NAME, UploadHistFactBean.CONCURRENT_PROGRAM_NAME, null, null, false, requestParameters); }
// считываем BLOB
public InputStream getFileForUploadId(){
StringBuffer strBuf = new StringBuffer();
InputStream dataStream = null;
String lQuery = "select file_data from DATA_UPLOADS where request_id = :1";
String res = "";
try
{
OracleCallableStatement statement = (OracleCallableStatement)connection.prepareCall(lQuery);
statement.setInt(1, requestId);
ResultSet resultSet = statement.executeQuery();
while (resultSet.next()) {
BLOB blob = ((OracleResultSet)resultSet).getBLOB(1);
dataStream = blob.getBinaryStream();
}
} catch (SQLException e)
{
throw OAException.wrapperException(e);
}
return dataStream;
} public void initialize(CpContext cpContext) throws SQLException,
XMLParseException,
SAXException,
IOException,
InstantiationException,
IllegalAccessException,
ClassNotFoundException,
NoSuchMethodException,
InvocationTargetException {
connection = cpContext.getJDBCConnection();
requestId = cpContext.getReqDetails().getRequestId();
logFile = cpContext.getLogFile();
reqCompletion = cpContext.getReqCompletion();
NameValueType parameter;
while (cpParameters.hasMoreElements()) {
parameter = cpParameters.nextParameter();
if ("p_upload_id".equalsIgnoreCase(parametr.getName())) {
this.uploadId = Integer.valueOf(parametr.getValue()).intValue();
}
}
public void runProgram(CpContext cpContext) {
try {
initialize(cpContext);
HashMap<String, String> inputParameters = new HashMap<String, String>();
inputParameters.put(DataInput.PARAMETER_PREFIX + "1", "oracle.apps.xxmy.test.bean.TemplateXML");
InputStream file = getFileForUploadId();
{ логика по распарсиванию файла Excel }
connection.commit();
// Успешно завершим конкаррент
Message normComplMessage = new Message("FND", "CONC-CP SUCCESSFUL TERMINATION");
reqCompletion.setCompletion(ReqCompletion.NORMAL, normComplMessage.getMessageText(cpContext.getResourceStore()));
} catch (Exception e) {
// Если произошла ошибка, нужно выставить конкаренту ошибочный статус и выдать в лог стек ошибки
reqCompletion.setCompletion(ReqCompletion.ERROR, e.getMessage());
StringWriter errStringWriter = new StringWriter();
PrintWriter errPrintWriter = new PrintWriter(errStringWriter, true);
e.printStackTrace(errPrintWriter);
logFile.writeln(errStringWriter.toString(), LogFile.ERROR);
} finally {
cpContext.releaseJDBCConnection();
}
}
3. Распарсивание XLS с помощью библиотеки POI. Шаблон oracle.apps.xxmy.test.bean.TemplateXML из шага 2 содержит набор параметров для вызова API вставки в таблицу с указанием данных о том, в каких ячейках брать значения. В нашем случае:<?xml version="1.0" encoding='windows-1251'?> <upload method="XXMY_TEST_PKG.upload_excel"> <element name="test" type="single"> <location src="sheet" sheet="Sheet1" row="0" col="0"/> </element> </upload>Пробегаясь по структуре данных и файлу данных, мы формируем вызов API:
begin XXMY_TEST_PKG.upload_excel(P_TEST => :1, P_REQUEST_ID => :2, P_UPLOAD_ID => :3, P_UPLOAD_METHOD => :4); end;Имея коллекции параметров и их значений, выполняем вызов:
public void doDbUpload() throws SQLException {
OracleCallableStatement statement = (OracleCallableStatement)connection.prepareCall(this.query);
ArrayList<Integer> keyList = new ArrayList<Integer>();
keyList.addAll(uploadParameters.keySet());
Collections.sort(keyList);
Iterator<Integer> parameterIterator = keyList.iterator();
while (parameterIterator.hasNext()) {
Integer parameterIndex = parameterIterator.next();
UploadParameter parameter = this.uploadParameters.get(parameterIndex);
statement.setString(parameterIndex.intValue(), parameter.getValue());
}
statement.execute();
statement.close();
}
Всё. Данные из файла отправляются в таблицу.BEGIN BNE_INTERFACE_COLS "2" //увеличивать это число OWNER = "ANONYMOUS" OBJECT_VERSION_NUMBER = "2" INTERFACE_COL_TYPE = "1" INTERFACE_COL_NAME = "LOAD_CODE" ENABLED_FLAG = "Y" REQUIRED_FLAG = "N" DISPLAY_FLAG = "Y" READ_ONLY_FLAG = "N" NOT_NULL_FLAG = "N" SUMMARY_FLAG = "N" MAPPING_ENABLED_FLAG = "Y" DATA_TYPE = "1" FIELD_SIZE = "22" DEFAULT_TYPE = "PARAMETER" DEFAULT_VALUE = "XXIP361_CODE" VAL_COMPONENT = "" "" DISPLAY_ORDER = "2" //увеличивать это число PROMPT_LEFT = "Код загрузки" PROMPT_ABOVE = "LOAD_CODE" LAST_UPDATE_DATE = "2013/05/24" VAL_QUERY = "" "" EXPANDED_SQL = "" "" END BNE_INTERFACE_COLS2. Добавление атрибутов в контент
BEGIN BNE_CONTENT_COLS "3" //увеличивать это число OBJECT_VERSION_NUMBER = "1" OWNER = "ANONYMOUS" COL_NAME = "PROJECT_CODE" USER_NAME = "PROJECT_CODE" LAST_UPDATE_DATE = "2013/05/24" READ_ONLY_FLAG = "N" END BNE_CONTENT_COLS3. Правка таблицы BNE_STORED_SQL. Запрос апдейтим напрямую, добавив новые поля интерфейсной таблицы.
BEGIN BNE_MAPPING_LINES "2" //увеличиваем это число INTERFACE_ASN = "XXMY" INTERFACE_CODE = "XXMY_LOAD_X_INTF1" INTERFACE_SEQ_NUM = "12" //ID атрибута интерфейса OWNER = "ANONYMOUS" DECODE_FLAG = "N" OBJECT_VERSION_NUMBER = "1" CONTENT_ASN = "XXRT" CONTENT_CODE = "XXMY_LOAD_CNT2" CONTENT_SEQ_NUM = "2" //ID атрибута контента LAST_UPDATE_DATE = "2013/05/24" END BNE_MAPPING_LINES5. Добавление атрибутов в LAYOUT (внимательно!)
BEGIN BNE_LAYOUT_COLS "520" //увеличиваем число с шагом в 10 OWNER = "APANIN" OBJECT_VERSION_NUMBER = "1" INTERFACE_ASN = "XXMY" INTERFACE_CODE = "XXMY_LOAD_X_INTF1" INTERFACE_SEQ_NUM = "45" //ID атрибута интерфейса DISPLAY_WIDTH = "15" LAST_UPDATE_DATE = "2014/02/13" READ_ONLY_FLAG = "N" END BNE_LAYOUT_COLSПосле этих манипуляций интегратор должен работать с новыми колонками.
with col_order as (select intr.interface_col_name, col.sequence_num from BNE_LAYOUTS_B lay, BNE_LAYOUT_BLOCKS_B blo, BNE_LAYOUT_COLS col, BNE_INTERFACE_COLS_B intr where lay.layout_code = blo.layout_code and blo.layout_code = col.layout_code and blo.block_id = col.block_id and intr.sequence_num = col.interface_seq_num and intr.interface_code = 'XXMY_LOAD_X_INTF1' and lay.layout_code = 'XXMY_CORRECT_LOAD' and blo.block_id = 2 //номер блока (1 - шапка документа) order by col.sequence_num) select co.interface_col_name, co.sequence_num from col_order co;Для изменения порядка делаем апдейт таблицы BNE_LAYOUT_COLS.
alter session set NLS_DATE_LANGUAGE = RUSSIANПоложим, в текущем месяце мы сделали 5 и 8 скворечников, а в следующем сделаем -5 и -8.
select pk, initcap(to_char(pivot_key, 'MONTH')) pivot_key, sum(value) value from (select 1 pk, sysdate pivot_key, 5 value from dual union select 1, sysdate, 8 from dual union select 1, sysdate + 31, -5 from dual union select 1, sysdate + 31, -8 from dual) group by pk, initcap(to_char(pivot_key, 'MONTH'))Развернем выборку, задав месяцы как колонки:
with a as
(select pk,
initcap(to_char(pivot_key, 'MONTH')) pivot_key,
sum(value) value
from (select 1 pk, sysdate pivot_key, 5 value from dual
union
select 1, sysdate, 8 from dual
union
select 1, sysdate + 31, -5 from dual
union
select 1, sysdate + 31, -8 from dual)
group by pk, initcap(to_char(pivot_key, 'MONTH'))
)
select pk, "'Январь'_MON" Jan,
"'Февраль'_MON" Feb
from (select *
from a pivot(sum(value) mon
FOR pivot_key IN('Январь',
'Февраль')
)
);PK JAN FEB
---------- ---------- ----------
1 Как видим, результат неверный. Обозначим месяц по-другому.with a as
(select pk,
to_char(pivot_key, 'MM') pivot_key,
sum(value) value
from (select 1 pk, sysdate pivot_key, 5 value from dual
union
select 1, sysdate, 8 from dual
union
select 1, sysdate + 31, -5 from dual
union
select 1, sysdate + 31, -8 from dual)
group by pk, to_char(pivot_key, 'MM')
)
select pk, "'01'_MON" Jan,
"'02'_MON" Feb
from (select *
from a pivot(sum(value) mon
FOR pivot_key IN('01',
'02')
)
);PK JAN FEB
---------- ---------- ----------
1 13 -13 Непонятно, в чем причина ошибки, но точно не в кириллических названиях.