Очень интересный проект по внедрению 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) Натягиваем данные на существующий шаблон XDO
select 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Непонятно, в чем причина ошибки, но точно не в кириллических названиях.