ODTUG Aggregator ODTUG Blogs http://localhost:8080 Tue, 14 Aug 2018 02:52:22 +0000 http://aggrssgator.com/ Extract records by APEX_STRING http://saeedhassanpour.blogspot.com/2018/08/extract-records-by-apexstring.html <div dir="ltr" style="text-align: left;" trbidi="on"><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-6xmXs3r9JpI/W2cAbZX-BiI/AAAAAAAAAz0/Et6EAfJEaOQNOapyIauxgmiSHaF5k8NwwCLcBGAs/s1600/extract_records.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="300" data-original-width="852" height="224" src="https://4.bp.blogspot.com/-6xmXs3r9JpI/W2cAbZX-BiI/AAAAAAAAAz0/Et6EAfJEaOQNOapyIauxgmiSHaF5k8NwwCLcBGAs/s640/extract_records.png" width="640" /></a></div><br /><a name='more'></a><div class="MsoNormal"><br /></div><div class="MsoNormal"><br /></div><div class="MsoNormal"><br /></div><div class="MsoNormal"><br /></div><div class="MsoNormal">I want to share my experience about to extract records by Query, so I am writing this article in order to explain it.<o:p></o:p></div><div class="MsoNormal"><br /></div><div class="MsoNormal">The examples in this article rely on the following test table. This sample used (+) for&nbsp;separating between string.</div><div class="MsoNormal"><br /></div><div class="MsoNormal"><b><span style="color: red;">Create table</span></b>&nbsp;<o:p></o:p></div><div class="MsoNormal"><br /></div><div class="MsoNormal"><pre class="brush: sql;">create table test_extract(f1 number, f2 varchar2(3000))<br />/<br /></pre></div><br /><div class="MsoNormal"><br /></div><div class="MsoNormal"><b><span style="color: red;">Insert sample data</span></b><o:p></o:p></div><div class="MsoNormal"><br /></div><div class="MsoNormal"><pre class="brush: sql;">insert into test_extract(f1,f2)<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; values(100,'MC0051+MC0053+MC0055+MC0059+MC0061+MC0134+MC0135+MC0136+MC0149+MC0150+MC0151')<br />/<br />insert into test_extract(f1,f2)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; values(200,'CR0219+CR0229')<br />/<br />commit<br />/<br /></pre></div><div class="MsoNormal"><br /></div><div class="MsoNormal"><b><span style="color: red;">Extract Query</span></b><o:p></o:p></div><div class="MsoNormal"><br /></div><pre class="brush: sql;">--Step 1<br /><br />--simple query<br /><br />SELECT f2 AS str,<br /><br /> f1 as SRL<br /><br />FROM test_extract<br /><br />/<br /><br />MC0051+MC0053+MC0055+MC0059+MC0061+MC0134+MC0135+MC0136+MC0149+MC0150+MC0151 100<br /><br />CR0219+CR0229 200<br /><br /><br />--Step 2<br /><br />--merge two fields<br /><br />SELECT REPLACE ( str, '+', ':' || SRL || '+') || ':' || SRL AS str,<br /><br /> SRL<br /><br />FROM (SELECT f2 AS str,<br /><br /> f1 as SRL<br /><br /> FROM test_extract<br /><br /> )<br /><br />/<br /><br /><br />MC0051:100+MC0053:100+MC0055:100+MC0059:100+MC0061:100+MC0134:100+MC0135:100+MC0136:100+MC0149:100+MC0150:100+MC0151:100 100<br /><br />CR0219:200+CR0229:200 200<br /><br /><br />--Step 3<br /><br />--makes one record<br /><br />--Here we see a simple example of the LISTAGG function, producing a comma-separated list of string<br /><br />SELECT LISTAGG (str, ',') WITHIN GROUP (ORDER BY SRL) AS str<br /><br />FROM (SELECT REPLACE ( str, '+', ':' || SRL || '+') || ':' || SRL AS str,<br /><br /> SRL<br /><br /> FROM (SELECT f2 AS str,<br /><br /> f1 as SRL<br /><br /> FROM test_extract<br /><br /> ))<br /><br />/<br /><br /><br />MC0051:100+MC0053:100+MC0055:100+MC0059:100+MC0061:100+MC0134:100+MC0135:100+MC0136:100+MC0149:100+MC0150:100+MC0151:100,CR0219:200+CR0229:200<br /><br /><br />--Step 4<br /><br />--In this section we create a dataset and nested table<br /><br />SELECT apex_string.split (REPLACE (str, ',', '+'), '+') AS str<br /><br />FROM (SELECT LISTAGG (str, ',') WITHIN GROUP (ORDER BY SRL) AS str<br /><br /> FROM (SELECT REPLACE ( str, '+', ':' || SRL || '+') || ':' || SRL AS str,<br /><br /> SRL<br /><br /> FROM (SELECT f2 AS str,<br /><br /> f1 as SRL<br /><br /> FROM test_extract<br /><br /> ))) <br /><br /> <br /><br />--Step 5<br /><br />--Final query that we get all records<br /><br />SELECT REGEXP_SUBSTR (COLUMN_VALUE, '[^:]+', 1, 1) "PARAM_VALUE", REGEXP_SUBSTR (COLUMN_VALUE, '[^:]+', 1, 2) "SRL"<br /><br />FROM TABLE (<br /><br /> SELECT apex_string.split (REPLACE (str, ',', '+'), '+') AS str<br /><br /> FROM (SELECT LISTAGG (str, ',') WITHIN GROUP (ORDER BY SRL) AS str<br /><br /> FROM (SELECT REPLACE ( str, '+', ':' || SRL || '+') || ':' || SRL AS str,<br /><br /> SRL<br /><br /> FROM (SELECT f2 AS str,<br /><br /> f1 as SRL<br /><br /> FROM test_extract<br /><br /> )))) <br /><br /><br />---result<br /><br />PARAM_VALUE SRL<br /><br />MC0051 100<br /><br />MC0053 100<br /><br />MC0055 100<br /><br />MC0059 100<br /><br />MC0061 100<br /><br />MC0134 100<br /><br />MC0135 100<br /><br />MC0136 100<br /><br />MC0149 100<br /><br />MC0150 100<br /><br />MC0151 100<br /><br />CR0219 200<br /><br /><br />CR0229 200 <br /><br /></pre><br /><div class="MsoNormal"><span font-size:="" xx-small=""><br /></span><span font-size:="" xx-small="">I hope to enjoy.</span></div><br /><div class="MsoNormal"><br /></div><div class="MsoNormal"><br /></div><div class="MsoNormal"><br /></div><div class="MsoNormal"><br /></div><br /></div> Saeed Hassanpour tag:blogger.com,1999:blog-2985988034075722260.post-4357062676059366814 Sat Aug 11 2018 08:16:00 GMT-0400 (EDT) Extract records by APEX_STRING https://saeedhassanpour.blogspot.com/2018/08/extract-records-by-apexstring.html <div dir="ltr" style="text-align: left;" trbidi="on"><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-6xmXs3r9JpI/W2cAbZX-BiI/AAAAAAAAAz0/Et6EAfJEaOQNOapyIauxgmiSHaF5k8NwwCLcBGAs/s1600/extract_records.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="300" data-original-width="852" height="224" src="https://4.bp.blogspot.com/-6xmXs3r9JpI/W2cAbZX-BiI/AAAAAAAAAz0/Et6EAfJEaOQNOapyIauxgmiSHaF5k8NwwCLcBGAs/s640/extract_records.png" width="640" /></a></div><br /><a name='more'></a><div class="MsoNormal"><br /></div><div class="MsoNormal"><br /></div><div class="MsoNormal"><br /></div><div class="MsoNormal"><br /></div><div class="MsoNormal">I want to share my experience about to extract records by Query, so I am writing this article in order to explain it.<o:p></o:p></div><div class="MsoNormal"><br /></div><div class="MsoNormal">The examples in this article rely on the following test table. This sample used (+) for&nbsp;separating between string.</div><div class="MsoNormal"><br /></div><div class="MsoNormal"><b><span style="color: red;">Create table</span></b>&nbsp;<o:p></o:p></div><div class="MsoNormal"><br /></div><div class="MsoNormal"><pre class="brush: sql;">create table test_extract(f1 number, f2 varchar2(3000))<br />/<br /></pre></div><br /><div class="MsoNormal"><br /></div><div class="MsoNormal"><b><span style="color: red;">Insert sample data</span></b><o:p></o:p></div><div class="MsoNormal"><br /></div><div class="MsoNormal"><pre class="brush: sql;">insert into test_extract(f1,f2)<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; values(100,'MC0051+MC0053+MC0055+MC0059+MC0061+MC0134+MC0135+MC0136+MC0149+MC0150+MC0151')<br />/<br />insert into test_extract(f1,f2)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; values(200,'CR0219+CR0229')<br />/<br />commit<br />/<br /></pre></div><div class="MsoNormal"><br /></div><div class="MsoNormal"><b><span style="color: red;">Extract Query</span></b><o:p></o:p></div><div class="MsoNormal"><br /></div><pre class="brush: sql;">--Step 1<br /><br />--simple query<br /><br />SELECT f2 AS str,<br /><br /> f1 as SRL<br /><br />FROM test_extract<br /><br />/<br /><br />MC0051+MC0053+MC0055+MC0059+MC0061+MC0134+MC0135+MC0136+MC0149+MC0150+MC0151 100<br /><br />CR0219+CR0229 200<br /><br /><br />--Step 2<br /><br />--merge two fields<br /><br />SELECT REPLACE ( str, '+', ':' || SRL || '+') || ':' || SRL AS str,<br /><br /> SRL<br /><br />FROM (SELECT f2 AS str,<br /><br /> f1 as SRL<br /><br /> FROM test_extract<br /><br /> )<br /><br />/<br /><br /><br />MC0051:100+MC0053:100+MC0055:100+MC0059:100+MC0061:100+MC0134:100+MC0135:100+MC0136:100+MC0149:100+MC0150:100+MC0151:100 100<br /><br />CR0219:200+CR0229:200 200<br /><br /><br />--Step 3<br /><br />--makes one record<br /><br />--Here we see a simple example of the LISTAGG function, producing a comma-separated list of string<br /><br />SELECT LISTAGG (str, ',') WITHIN GROUP (ORDER BY SRL) AS str<br /><br />FROM (SELECT REPLACE ( str, '+', ':' || SRL || '+') || ':' || SRL AS str,<br /><br /> SRL<br /><br /> FROM (SELECT f2 AS str,<br /><br /> f1 as SRL<br /><br /> FROM test_extract<br /><br /> ))<br /><br />/<br /><br /><br />MC0051:100+MC0053:100+MC0055:100+MC0059:100+MC0061:100+MC0134:100+MC0135:100+MC0136:100+MC0149:100+MC0150:100+MC0151:100,CR0219:200+CR0229:200<br /><br /><br />--Step 4<br /><br />--In this section we create a dataset and nested table<br /><br />SELECT apex_string.split (REPLACE (str, ',', '+'), '+') AS str<br /><br />FROM (SELECT LISTAGG (str, ',') WITHIN GROUP (ORDER BY SRL) AS str<br /><br /> FROM (SELECT REPLACE ( str, '+', ':' || SRL || '+') || ':' || SRL AS str,<br /><br /> SRL<br /><br /> FROM (SELECT f2 AS str,<br /><br /> f1 as SRL<br /><br /> FROM test_extract<br /><br /> ))) <br /><br /> <br /><br />--Step 5<br /><br />--Final query that we get all records<br /><br />SELECT REGEXP_SUBSTR (COLUMN_VALUE, '[^:]+', 1, 1) "PARAM_VALUE", REGEXP_SUBSTR (COLUMN_VALUE, '[^:]+', 1, 2) "SRL"<br /><br />FROM TABLE (<br /><br /> SELECT apex_string.split (REPLACE (str, ',', '+'), '+') AS str<br /><br /> FROM (SELECT LISTAGG (str, ',') WITHIN GROUP (ORDER BY SRL) AS str<br /><br /> FROM (SELECT REPLACE ( str, '+', ':' || SRL || '+') || ':' || SRL AS str,<br /><br /> SRL<br /><br /> FROM (SELECT f2 AS str,<br /><br /> f1 as SRL<br /><br /> FROM test_extract<br /><br /> )))) <br /><br /><br />---result<br /><br />PARAM_VALUE SRL<br /><br />MC0051 100<br /><br />MC0053 100<br /><br />MC0055 100<br /><br />MC0059 100<br /><br />MC0061 100<br /><br />MC0134 100<br /><br />MC0135 100<br /><br />MC0136 100<br /><br />MC0149 100<br /><br />MC0150 100<br /><br />MC0151 100<br /><br />CR0219 200<br /><br /><br />CR0229 200 <br /><br /></pre><br /><div class="MsoNormal"><span font-size:="" xx-small=""><br /></span><span font-size:="" xx-small="">I hope to enjoy.</span></div><br /><div class="MsoNormal"><br /></div><div class="MsoNormal"><br /></div><div class="MsoNormal"><br /></div><div class="MsoNormal"><br /></div><br /></div> Saeed Hassanpour tag:blogger.com,1999:blog-2985988034075722260.post-4357062676059366814 Sat Aug 11 2018 08:16:00 GMT-0400 (EDT) Quick PL/SQL, a code generator for PL/SQL based on simple markup https://ora-00001.blogspot.com/2018/08/quick-plsql-code-generator-for-plsql.html Maybe you've heard about "<a href="https://apex.oracle.com/en/quicksql/">Quick SQL</a>", a utility (previously a separate application, now part of APEX 18.1 itself) that generates SQL scripts based on a simple markup language. Quick SQL is a real time-saver and allows you to go from idea to prototype to working application in an instant.<br /><br />Inspired by Quick SQL, I've created a similar utility, called "Quick PL/SQL", that does the same thing, except it generates PL/SQL code (packages with functions and procedures, with standard comment blocks, formatting, etc.) based on a simple markup.<br /><br />I've recorded a couple of videos to show the tool in action.<br /><br />Here is an introduction which explains the basic input syntax and the output options:<br /><br /><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/ED0soNWu580/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/ED0soNWu580?feature=player_embedded" width="320"></iframe></div><br /><br />And here is another video which explains how to create standard CRUD-style (Create, Read, Update, Delete) APIs for your tables:<br /><br /><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/10BBNh15jlc/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/10BBNh15jlc?feature=player_embedded" width="320"></iframe></div><br /><br />Try it out for yourself here: <a href="https://apex.oracle.com/pls/apex/f?p=QUICKPLSQL:HOME">https://apex.oracle.com/pls/apex/f?p=QUICKPLSQL:HOME</a> or via this shortcut: <a href="https://tinyurl.com/quickplsql">https://tinyurl.com/quickplsql</a><br /><br />Of course, I wouldn't mind if this functionality becomes available as part of the QuickSQL utility that is built into APEX! :-)<br /><br /><br /> Morten Braten tag:blogger.com,1999:blog-5215551487816981140.post-9202435483024687876 Thu Aug 09 2018 06:10:00 GMT-0400 (EDT) Integrando Oracle JET 5.1 + Apache Tomcat y Oracle Apex 5.1 / 18.1 + Ords + Local Machine https://aflorestorres.blogspot.com/2018/08/integrando-oracle-jet-51-apache-tomcat.html Como ya vimos en un tutorial anterior integramos Oracle <b>Jet 5.1</b> en <b>Apex 5.1</b> usando librerias online de Oracle, Ahora haremos un proceso similar, pero usando librerias de nuestro servidor local, para esta demo usare <b>Apache Tomcat</b> para subir las librerias.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-pHnhL3U8vq8/W2fD26eUMTI/AAAAAAAAM_U/Unj1HOAXV4oCHn79MCC_yKLWakWYaLM3gCLcBGAs/s1600/Titulo.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="386" data-original-width="795" height="193" src="https://1.bp.blogspot.com/-pHnhL3U8vq8/W2fD26eUMTI/AAAAAAAAM_U/Unj1HOAXV4oCHn79MCC_yKLWakWYaLM3gCLcBGAs/s400/Titulo.PNG" width="400" /></a></div><br /><br /><a href="https://aflorestorres.blogspot.com/2018/07/integrando-oracle-jet-v51-en-oracle.html" target="_blank">Link Integrando Jet 5.1 con Apex</a><br /><a href="https://aflorestorres.blogspot.com/2018/04/instalando-ords-apache-tomcat-en.html" target="_blank">Link Instalando Apache Tomcat + Apex + Ords.</a><br /><br />Primero descargamos las librerias de JET de la pagina oficial de Oracle.<br /><a href="http://www.oracle.com/technetwork/developer-tools/jet/downloads/index.html" target="_blank">Link</a><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-u6mmplcessE/W2fD0-tvdrI/AAAAAAAAM_A/-A1CBUP8af0QUaUeBSoRTO6CVpGDPwL9QCLcBGAs/s1600/1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="123" data-original-width="396" height="99" src="https://2.bp.blogspot.com/-u6mmplcessE/W2fD0-tvdrI/AAAAAAAAM_A/-A1CBUP8af0QUaUeBSoRTO6CVpGDPwL9QCLcBGAs/s320/1.png" width="320" /></a></div><br /><br />Extraemos el contenido en un directorio que nos sea de facil acceso, en mi caso lo puse junto a la instacion de Apex que tengo.&nbsp;<b>C:\Install_Apex\Jet_5.1</b><br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-j-po8qW6iMA/W2fD1FFHdAI/AAAAAAAAM_I/pKMIKFOIgrcrmdOFfh9YhdGOG1jwK2mKQCLcBGAs/s1600/2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="317" data-original-width="374" src="https://1.bp.blogspot.com/-j-po8qW6iMA/W2fD1FFHdAI/AAAAAAAAM_I/pKMIKFOIgrcrmdOFfh9YhdGOG1jwK2mKQCLcBGAs/s1600/2.png" /></a></div><br /><br />Vamos donde esta instalado Apache Tomcat y editamos el archivo <b>SERVER.XML</b> dentro del directorio de conf.&nbsp; <b>C:\Program Files\Apache Software Foundation\Tomcat 9.0\conf</b><br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-s59-Q-ZSR_c/W2fD1F6lbSI/AAAAAAAAM_E/R_EfjEBzWzMahUNBuZ7TqppSNAN3pDA3wCLcBGAs/s1600/3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="332" data-original-width="687" src="https://1.bp.blogspot.com/-s59-Q-ZSR_c/W2fD1F6lbSI/AAAAAAAAM_E/R_EfjEBzWzMahUNBuZ7TqppSNAN3pDA3wCLcBGAs/s1600/3.png" /></a></div><br /><br />Agregamos la referencia a donde estan nuestras librerias de <b>Oracle Jet y el path;</b> En mi caso le puse "<b>Jet_5.1</b>" , puedes colocar el que gustes.<br /><br /><div style="text-align: center;"><b>&lt;Context docBase="C:\Install_Apex\Jet_5.1" path="/Jet_5.1" /&gt;</b></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-_8K6gu0wWjw/W2fD1onMoqI/AAAAAAAAM_M/RQrL4_e91ME1ulZm5kjZOvYhO2B0iG3_QCLcBGAs/s1600/4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="531" data-original-width="650" src="https://1.bp.blogspot.com/-_8K6gu0wWjw/W2fD1onMoqI/AAAAAAAAM_M/RQrL4_e91ME1ulZm5kjZOvYhO2B0iG3_QCLcBGAs/s1600/4.png" /></a></div><br />Guardamos los cambios y reiniciamos apache tomcat.<br />Podemos verificar si esta correctamente accediendo a un link como este, en tu caso puede variar por el puerto o nombre que le colocaste.<br /><br /><b>http://127.0.0.1:8080/Jet_5.1/js/libs/knockout/knockout-3.4.2.js</b><br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-UHAFQAx1MpU/W2fD17fVVOI/AAAAAAAAM_Q/V5hqYs8Iu5gp7fcOzfmn0Iz50VjTvwdAQCLcBGAs/s1600/5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="292" data-original-width="591" src="https://1.bp.blogspot.com/-UHAFQAx1MpU/W2fD17fVVOI/AAAAAAAAM_Q/V5hqYs8Iu5gp7fcOzfmn0Iz50VjTvwdAQCLcBGAs/s1600/5.png" /></a></div><br /><br />Cambiamos las referencias que teniamos en nuestra aplicacion apex, algo similar a esto (dependiendo de que puerto tengas configurado y directorio, cambiara. En mi caso&nbsp;<span style="background-color: #fff0f0;"><b>http://127.0.0.1:8080/Jet_5.1</b></span><br /><br /><!-- HTML generated using hilite.me --><br /><div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0;">define(<span style="background-color: #fff0f0;">"knockout"</span>,[],<span style="color: #008800; font-weight: bold;">function</span>(){<span style="color: #008800; font-weight: bold;">return</span> ko;});<br /><br /><br />requirejs<span style="color: #6600ee; font-weight: bold;">.</span>config({<br /> <span style="color: #333333;">//</span> <span style="color: #007020;">Path</span> mappings <span style="color: #008800; font-weight: bold;">for</span> the logical module <span style="color: #008800; font-weight: bold;">names</span><br /> paths: { <br /> <span style="color: #333333;">//</span><span style="background-color: #fff0f0;">'knockout'</span>: <span style="background-color: #fff0f0;">'https://static.oracle.com/cdn/jet/v5.1.0/3rdparty/knockout/knockout-3.4.2'</span>,<br /> <span style="background-color: #fff0f0;">'knockout'</span>: <span style="background-color: #fff0f0;">'http://127.0.0.1:8080/Jet_5.1/js/libs/knockout/knockout-3.4.2'</span>, <br /> <span style="background-color: #fff0f0;">'jquery'</span>: <span style="background-color: #fff0f0;">'http://127.0.0.1:8080/Jet_5.1/js/libs/jquery/jquery-3.3.1.min'</span>,<br /> <span style="background-color: #fff0f0;">'jqueryui-amd'</span>: <span style="background-color: #fff0f0;">'http://127.0.0.1:8080/Jet_5.1/js/libs/jquery/jqueryui-amd-1.12.1.min'</span>,<br /> <span style="background-color: #fff0f0;">'ojs'</span>: <span style="background-color: #fff0f0;">'http://127.0.0.1:8080/Jet_5.1/js/libs/oj/v5.1.0/min'</span>,<br /> <span style="color: #333333;">//</span><span style="background-color: #fff0f0;">'ojs'</span>: <span style="background-color: #fff0f0;">'https://static.oracle.com/cdn/jet/v5.1.0/default/js/min'</span>, <br /> <span style="background-color: #fff0f0;">'ojL10n'</span>: <span style="background-color: #fff0f0;">'http://127.0.0.1:8080/Jet_5.1/js/libs/oj/v5.1.0/ojL10n'</span>,<br /> <span style="background-color: #fff0f0;">'ojtranslations'</span>: <span style="background-color: #fff0f0;">'http://127.0.0.1:8080/Jet_5.1/js/libs/oj/v5.1.0/resources'</span>,<br /> <span style="background-color: #fff0f0;">'text'</span>: <span style="background-color: #fff0f0;">'http://127.0.0.1:8080/Jet_5.1/js/libs/require/text'</span>,<br /> <span style="background-color: #fff0f0;">'promise'</span>: <span style="background-color: #fff0f0;">'http://127.0.0.1:8080/Jet_5.1/js/libs/es6-promise/es6-promise.min'</span>,<br /> <span style="background-color: #fff0f0;">'hammerjs'</span>: <span style="background-color: #fff0f0;">'http://127.0.0.1:8080/Jet_5.1/js/libs/hammer/hammer-2.0.8.min'</span>,<br /> <span style="background-color: #fff0f0;">'signals'</span>: <span style="background-color: #fff0f0;">'http://127.0.0.1:8080/Jet_5.1/js/libs/js-signals/signals.min'</span>,<br /> <span style="background-color: #fff0f0;">'ojdnd'</span>: <span style="background-color: #fff0f0;">'http://127.0.0.1:8080/Jet_5.1/js/libs/dnd-polyfill/dnd-polyfill-1.0.0.min'</span>,<br /> <span style="background-color: #fff0f0;">'css'</span>: <span style="background-color: #fff0f0;">'http://127.0.0.1:8080/Jet_5.1/js/libs/require-css/css.min'</span>,<br /> <span style="background-color: #fff0f0;">'customElements'</span>: <span style="background-color: #fff0f0;">'http://127.0.0.1:8080/Jet_5.1/js/libs/webcomponents/custom-elements.min'</span>,<br /> <span style="background-color: #fff0f0;">'proj4js'</span>: <span style="background-color: #fff0f0;">'http://127.0.0.1:8080/Jet_5.1/js/libs/proj4js/dist/proj4'</span><br /> },<br /> <span style="color: #333333;">//</span> Shim configurations <span style="color: #008800; font-weight: bold;">for</span> modules that <span style="color: #008800; font-weight: bold;">do</span> <span style="color: #008800; font-weight: bold;">not</span> expose AMD<br /> shim: {<br /> <span style="background-color: #fff0f0;">'jquery'</span>: {<br /> exports: [<span style="background-color: #fff0f0;">'jQuery'</span>, <span style="background-color: #fff0f0;">'$'</span>]<br /> }<br /> }<br />});<br /></pre></div><br />Agregamos las referencias a knockout y require.js<br /><br /><!-- HTML generated using hilite.me --><br /><div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0;">http:<span style="color: #333333;">//</span><span style="color: #6600ee; font-weight: bold;">127.0.0.1</span>:<span style="color: #6600ee; font-weight: bold;">8080</span><span style="color: #333333;">/</span>Jet_5<span style="color: #6600ee; font-weight: bold;">.1</span><span style="color: #333333;">/</span>js<span style="color: #333333;">/</span>libs<span style="color: #333333;">/</span>knockout<span style="color: #333333;">/</span>knockout<span style="color: #333333;">-</span><span style="color: #6600ee; font-weight: bold;">3.4.2.</span>js<br />http:<span style="color: #333333;">//</span><span style="color: #6600ee; font-weight: bold;">127.0.0.1</span>:<span style="color: #6600ee; font-weight: bold;">8080</span><span style="color: #333333;">/</span>Jet_5<span style="color: #6600ee; font-weight: bold;">.1</span><span style="color: #333333;">/</span>js<span style="color: #333333;">/</span>libs<span style="color: #333333;">/</span>require<span style="color: #333333;">/</span>require<span style="color: #6600ee; font-weight: bold;">.</span>js<br /></pre></div><br />Agremos la referencia a las librerias de<b> CSS</b><br /><br />Quiero comentar que cuando agregamos las librerias de CSS de JET en mi post anterior,&nbsp; estas estaban sobreescribiendo las de Apex, asi que junto a <a href="https://rimblas.com/blog/" target="_blank">Jorge Rimblas</a>, me comento que el mejor camino es referenciar librerias Css de Apex.<br /><br />Para Apex 18.1&nbsp; podemos usar :<br /><!-- HTML generated using hilite.me --><br /><div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #003388; font-weight: bold;">#JET_CSS_DIRECTORY</span><span style="color: #333333;">#/</span>alta<span style="color: #333333;">/</span>oj<span style="color: #333333;">-</span>alta<span style="color: #333333;">-</span>notag<span style="color: #333333;">-</span>min<span style="color: #6600ee; font-weight: bold;">.</span>css<span style="color: #333333;">?</span>v<span style="color: #333333;">=</span><span style="color: #6600ee; font-weight: bold;">18.1.0.00.45</span><br /></pre></div><br />y para Apex 5.1:<br /><!-- HTML generated using hilite.me --><br /><div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #003388; font-weight: bold;">#JET_CSS_DIRECTORY</span><span style="color: #333333;">#/</span>alta<span style="color: #333333;">/</span>oj<span style="color: #333333;">-</span>alta<span style="color: #333333;">-</span>notag<span style="color: #333333;">-</span>min<span style="color: #6600ee; font-weight: bold;">.</span>css<br /></pre></div><br />...<br /><!-- HTML generated using hilite.me --><br /><div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #333333;">&lt;</span>script<span style="color: #333333;">&gt;</span><br /> <span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span><span style="color: #008800; font-weight: bold;">document</span><span style="color: #6600ee; font-weight: bold;">.</span>createElement) {<br /> <span style="color: #008800; font-weight: bold;">document</span><span style="color: #6600ee; font-weight: bold;">.</span>createElement <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">document</span><span style="color: #6600ee; font-weight: bold;">.</span>constructor<span style="color: #6600ee; font-weight: bold;">.</span>prototype<span style="color: #6600ee; font-weight: bold;">.</span>createElement;<br /> <span style="color: #008800; font-weight: bold;">document</span><span style="color: #6600ee; font-weight: bold;">.</span>createElementNS <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">document</span><span style="color: #6600ee; font-weight: bold;">.</span>constructor<span style="color: #6600ee; font-weight: bold;">.</span>prototype<span style="color: #6600ee; font-weight: bold;">.</span>createElementNS;<br /> <span style="color: #008800; font-weight: bold;">document</span><span style="color: #6600ee; font-weight: bold;">.</span>importNode <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">document</span><span style="color: #6600ee; font-weight: bold;">.</span>constructor<span style="color: #6600ee; font-weight: bold;">.</span>prototype<span style="color: #6600ee; font-weight: bold;">.</span>importNode;<br /> }<br /><br /> <span style="color: #333333;">//</span> The <span style="background-color: #fff0f0;">"oj_whenReady"</span> <span style="color: #008800; font-weight: bold;">global</span> variable enables a strategy that the busy context whenReady,<br /> <span style="color: #333333;">//</span> will implicitly <span style="color: #008800; font-weight: bold;">add</span> a busy state, <span style="color: #008800; font-weight: bold;">until</span> the application calls applicationBoostrapComplete<br /> <span style="color: #333333;">//</span> <span style="color: #008800; font-weight: bold;">on</span> the busy state context<span style="color: #6600ee; font-weight: bold;">.</span><br /> <span style="color: #008800; font-weight: bold;">window</span>[<span style="background-color: #fff0f0;">"oj_whenReady"</span>] <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">true</span>;<br /><span style="color: #333333;">&lt;/</span>script<span style="color: #333333;">&gt;</span><br /></pre></div><br />Deberia quedar de esta forma:<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-E2P7iEdauTM/W2h15hdYZ4I/AAAAAAAANAk/hJwZttjphwUyBSAkzesXCAaf5B1o5S_FwCLcBGAs/s1600/7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="570" data-original-width="992" src="https://4.bp.blogspot.com/-E2P7iEdauTM/W2h15hdYZ4I/AAAAAAAANAk/hJwZttjphwUyBSAkzesXCAaf5B1o5S_FwCLcBGAs/s1600/7.png" /></a></div><br /><br /><br /><br />Por ultimo para comprobar agregamos un PictoChart ... similar a lo que hicimos aqui.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-icrsvt22WVc/W2fGDEELayI/AAAAAAAAM_w/eu3odKqMvMsIJkoIIWguQPMv6vyJgKabQCLcBGAs/s1600/6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="652" data-original-width="1359" src="https://1.bp.blogspot.com/-icrsvt22WVc/W2fGDEELayI/AAAAAAAAM_w/eu3odKqMvMsIJkoIIWguQPMv6vyJgKabQCLcBGAs/s1600/6.png" /></a></div><br /><br />Y vemos como se cargaron las librerias de nuestro servidor local.<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /> Angel O. Flores Torres tag:blogger.com,1999:blog-2893325831811936253.post-8407027118739858970 Mon Aug 06 2018 22:44:00 GMT-0400 (EDT) Migrating Subversion to Git with LFS http://barrymcgillin.blogspot.com/2018/08/migrating-subversion-to-git-with-lfs.html <script src="https://cdnjs.cloudflare.com/ajax/libs/prettify/r298/run_prettify.min.js"></script> When a project has been on the go for a while theres going to be all sorts of stuff in there from jars to zips and everything in between. &nbsp;We went though this a while ago and wanting to keep all the history, we needed a way to prune the history of all the big files and weird things we were not going to move to git. <br /><br />Now we knew we had some large files, namely binary files like jars which were build dependencies before we moved to artifactory for a lot of it. &nbsp;So, before we start we need to make sure that git is installed, and git-lfs. &nbsp;Git-lfs should be on the path so git can find it and you'll need to make sure git svn can run. &nbsp;You'll need perl and &nbsp;to run cpan (Comprehensive Perl Archive Network) to install the SVN::Core modules.<br /><br /><h2>Initialisation</h2>As a test to start, make sure git and git lfs are on the path and that git svn runs.<br /><br /><div style="background-color: #dfdbc3; color: #4324d4; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="color: #ee1807; font-variant-ligatures: no-common-ligatures;">bamcgill</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">@</span><span style="font-variant-ligatures: no-common-ligatures;">bamcgill-mac[</span><span style="color: #00a3af; font-variant-ligatures: no-common-ligatures;">~</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">]&nbsp;</span></div><div style="background-color: #dfdbc3; color: #4d2f2d; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="font-variant-ligatures: no-common-ligatures;">- $ git --version</span></div><div style="background-color: #dfdbc3; color: #4d2f2d; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="font-variant-ligatures: no-common-ligatures;">git version 2.15.2 (Apple Git-101.1)</span></div><div style="background-color: #dfdbc3; color: #4324d4; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="color: #ee1807; font-variant-ligatures: no-common-ligatures;">bamcgill</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">@</span><span style="font-variant-ligatures: no-common-ligatures;">bamcgill-mac[</span><span style="color: #00a3af; font-variant-ligatures: no-common-ligatures;">~</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">]&nbsp;</span></div><div style="background-color: #dfdbc3; color: #4d2f2d; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="font-variant-ligatures: no-common-ligatures;">- $ git lfs version</span></div><div style="background-color: #dfdbc3; color: #4d2f2d; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="font-variant-ligatures: no-common-ligatures;">git-lfs/2.3.4 (GitHub; darwin amd64; go 1.9.1)</span></div><div style="background-color: #dfdbc3; color: #4324d4; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="color: #ee1807; font-variant-ligatures: no-common-ligatures;">bamcgill</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">@</span><span style="font-variant-ligatures: no-common-ligatures;">bamcgill-mac[</span><span style="color: #00a3af; font-variant-ligatures: no-common-ligatures;">~</span><span style="color: black; font-variant-ligatures: no-common-ligatures;">]&nbsp;</span></div><div style="background-color: #dfdbc3; color: #4d2f2d; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="font-variant-ligatures: no-common-ligatures;">- $ git svn</span></div><div style="background-color: #dfdbc3; color: #4d2f2d; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="font-variant-ligatures: no-common-ligatures;">git-svn - bidirectional operations between a single Subversion tree and git</span></div><div style="background-color: #dfdbc3; color: #4324d4; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"></div><div style="background-color: #dfdbc3; color: #4d2f2d; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="font-variant-ligatures: no-common-ligatures;">usage: git svn <command></command> [options] [arguments]</span></div><div><span style="font-variant-ligatures: no-common-ligatures;"><br /></span></div><h2><span style="font-variant-ligatures: no-common-ligatures;">Clone Empty GIT Repository</span></h2>Before the migration, we should create an empty repository for importing the subversion repository into. &nbsp;Then we can clone it to start the migration<br /><br /><pre class="prettyprint"><code class="language-sh">git clone git@gitlab.yourcompany.com:group-name/gitrepo.git </code></pre><pre class="prettyprint"><code class="language-sh"><br /></code></pre><h2>Clone the subversion repository into the empty git repository</h2><div>Before we do the clone, we need to build a file of the authors on the svn</div><br /><pre class="prettyprint"><code class="language-sh">svn log -q | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" &lt;"$2"&gt;"}' | aort -u &gt; authors.txt </code></pre><br />Now we need to edit that file which has a format like this<br /><div style="background-color: #dfdbc3; color: #4d2f2d; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="font-variant-ligatures: no-common-ligatures;">bamcgill = bamcgill <bamcgill></bamcgill></span></div><div><span style="font-variant-ligatures: no-common-ligatures;">to a format like this</span></div><div><span style="font-variant-ligatures: no-common-ligatures;"></span><br /><div style="background-color: #dfdbc3; color: #4d2f2d; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="font-variant-ligatures: no-common-ligatures;"><span style="font-variant-ligatures: no-common-ligatures;">bamcgill = Barry McGillin <barry mcgillin.com=""></barry></span></span></div><span style="font-variant-ligatures: no-common-ligatures;"><div><span style="font-variant-ligatures: no-common-ligatures;">This file is then used to map the users in subversion to the new decorated users in git.</span></div><div><span style="font-variant-ligatures: no-common-ligatures;"><br /></span></div></span></div><pre class="prettyprint"><code class="language-sh">git svn clone https://server.company.com/svn/project/trunk gitrepo --authors-file=authors.txt &gt; loglog 2&gt;&amp;1 </code></pre><pre class="prettyprint"><code class="language-sh"><br /></code></pre>We push the output into a log file because it takes ages and you can scroll back and see where the actual clone is. &nbsp;This pulls the entire history from revision 1 to HEAD and drops it into the git repository<br /><br /><h2>Clean up the GIT Repository Metadata&nbsp;</h2>Now, we use a really handy utility: BFG: Removes large or troublesome blobs like git-filter-branch does. For this exercise we run the utility twice. Once to strip blobs larger than 1M <br /><br /><pre class="prettyprint"><code class="language-sh">java -jar bfg-1.13.0.jar --strip-blobs-bigger-than 1M git-repo </code></pre><pre class="prettyprint"><code class="language-sh"><br /></code></pre><pre class="prettyprint"><code class="language-sh">Now fix the changes into the repository. </code></pre><pre class="prettyprint"><code class="language-sh"><br /></code></pre><pre class="prettyprint"><code class="language-sh">cd git-repo &amp;&amp; git reflog expire --expire=now --all &amp;&amp; git gc --prune=now --aggressive &amp;&amp; cd - </code></pre><pre class="prettyprint"><code class="language-sh"><br /></code></pre>Now for the second run of the BFG, we want to convert a bunch of things like binary files to Large File Storage <br /><br /><pre class="prettyprint"><code class="language-sh">java -jar bfg-1.13.0.jar --convert-to-git-lfs "*.{rar,dll,zip,war,gz,jar,tar,opar,dmp,serial,exe,mde,gif,msg,oxd_db,dylib,so}" --no-blob-protection git-repo</code> </pre><pre class="prettyprint"><code class="language-sh"><br /></code></pre><pre class="prettyprint"><code class="language-sh">And fix that into the repository too.</code></pre><pre class="prettyprint"><code class="language-sh"><br /></code></pre><pre class="prettyprint"><code class="language-sh">cd sql-developer &amp;&amp; git reflog expire --expire=now --all &amp;&amp; git gc --prune=now --aggressive &amp;&amp; cd - </code></pre><br /><h2>Install and Configure GIT LFS</h2><div>Create an file called .lfsconfig which has your preconfigured LFS server<br /><br /></div><pre class="prettyprint"><code class="language-sh">$cp lfsconfig git/.lfsconfig&nbsp;<br />$cat .lfsconfig<br />[lfs]<br /> url = https://artifactory.yourcorp.com/api/lfs/git-lfs<br /></code></pre><pre class="prettyprint"><code class="language-sh"> </code></pre>Now, you need to install lfs into the repository.<br /><br /><pre class="prettyprint"><code class="language-sh">cd git-repo &amp;&amp; git lfs install </code></pre><br />and then track all the binary and large files you want<br /><br /><pre class="prettyprint"><code class="language-sh">git lfs track *.{rar,dll,zip,war,gz,jar,tar,opar,dmp,serial,exe,mde,gif,msg,oxd_db,dylib,so} </code></pre><br /><h2>Commit and Push</h2>Next we need to add the files we just edited AND the base directory of the git repository as all the binary files will be swapped out to LFS on push<br /><br /><pre class="prettyprint"><code class="language-sh">git add .lfsconfig .gitattributes &amp;&amp; git add .</code></pre><br /><pre class="prettyprint"><code class="language-sh">git commit -m "initial commit to git" &amp;&amp; git push origin master </code></pre><br />Depending on the security setting of your artifactory repository you may be prompted for a username and password for pushing the binary files to LFS and then the references and files will be pushed to your remote git repository<br /><br /><h2>Summary</h2>It took us a couple of goes to get this right so we put it in a file to rerun when it died (it will til you get all the large file extensions listed)<br />Heres the contents of that script you can grab and use for your migration.<br />Have fun.<br /><br /><div style="background-color: #dfdbc3; color: #4d2f2d; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="font-variant-ligatures: no-common-ligatures;">git clone git@gitlab.yourcompany.com:group-dev/git-repo.git &amp;&amp; \</span></div><div style="background-color: #dfdbc3; color: #4d2f2d; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="font-variant-ligatures: no-common-ligatures;">git svn clone https://svn.yourcompany.com/svn/project/trunk&nbsp;git-repo&nbsp;--authors-file=authors.txt &gt; loglog 2&gt;&amp;1 &amp;&amp; \</span></div><div style="background-color: #dfdbc3; color: #4d2f2d; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="font-variant-ligatures: no-common-ligatures;">java -jar bfg-1.13.0.jar --strip-blobs-bigger-than 1M&nbsp;git-repo&nbsp;&amp;&amp; \</span></div><div style="background-color: #dfdbc3; color: #4d2f2d; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="font-variant-ligatures: no-common-ligatures;">cd&nbsp;git-repo&nbsp;&amp;&amp; git reflog expire --expire=now --all &amp;&amp; git gc --prune=now --aggressive &amp;&amp; cd - &amp;&amp; \</span></div><div style="background-color: #dfdbc3; color: #4d2f2d; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="font-variant-ligatures: no-common-ligatures;">java -jar bfg-1.13.0.jar --convert-to-git-lfs "*.{rar,dll,zip,war,gz,jar,tar,opar,dmp,serial,exe,mde,gif,msg,oxd_db,dylib,so}" --no-blob-protection&nbsp;git-repo&nbsp;&amp;&amp; \</span></div><div style="background-color: #dfdbc3; color: #4d2f2d; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="font-variant-ligatures: no-common-ligatures;">cd&nbsp;git-repo&nbsp;&amp;&amp; git reflog expire --expire=now --all &amp;&amp; git gc --prune=now --aggressive &amp;&amp; cd - &amp;&amp; \</span></div><div style="background-color: #dfdbc3; color: #4d2f2d; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="font-variant-ligatures: no-common-ligatures;">cp lfsconfig&nbsp;git-repo/.lfsconfig &amp;&amp; \</span></div><div style="background-color: #dfdbc3; color: #4d2f2d; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="font-variant-ligatures: no-common-ligatures;">cd&nbsp;git-repo&nbsp;&amp;&amp; \</span></div><div style="background-color: #dfdbc3; color: #4d2f2d; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="font-variant-ligatures: no-common-ligatures;">git lfs install &amp;&amp; \</span></div><div style="background-color: #dfdbc3; color: #4d2f2d; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="font-variant-ligatures: no-common-ligatures;">git lfs track *.{rar,dll,zip,war,gz,jar,tar,opar,dmp,serial,exe,mde,gif,msg,oxd_db,dylib,so} &amp;&amp; \</span></div><div style="background-color: #dfdbc3; color: #4d2f2d; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="font-variant-ligatures: no-common-ligatures;">git add .lfsconfig .gitattributes &amp;&amp; \</span></div><div style="background-color: #dfdbc3; color: #4d2f2d; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="font-variant-ligatures: no-common-ligatures;">git add . &amp;&amp; \</span></div><div style="background-color: #dfdbc3; color: #4d2f2d; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="font-variant-ligatures: no-common-ligatures;">git commit -m "initial commit to git" &amp;&amp; \</span></div><br /><div style="background-color: #dfdbc3; color: #4d2f2d; font-family: Courier; font-size: 14px; font-stretch: normal; line-height: normal;"><span style="font-variant-ligatures: no-common-ligatures;">git push origin master</span></div><div><span style="font-variant-ligatures: no-common-ligatures;"><br /></span></div> Barry McGillin tag:blogger.com,1999:blog-1555497785494345295.post-416440334734188494 Fri Aug 03 2018 14:36:00 GMT-0400 (EDT) Easy XLSX Parser: Just with SQL and PL/SQL https://blogs.oracle.com/apex/easy-xlsx-parser%3A-just-with-sql-and-plsql <p style="text-align: justify;">Uploading XLSX files is a very common requirement these days. Application Express at this time only supports uploading CSV files out of the box. The community provides quite a few blog postings and also plug-ins; most of these store the data into a collection, which makes it hard to parse an XLSX outside of an APEX context, e.g. in the background using a scheduler job.</p> <p style="text-align: justify;">This blog posting shows a method to parse XLSX files with only SQL and PL/SQL. The actual work will be done by a table function, thus no collections and no APEX session is required. Since a table function returns rows and columns, one can easily insert the results into a table, apply some transformation logic, push it into the background with a scheduler job or just display.</p> <p style="text-align: justify;">The XLSX format is based on XML: an XSLX file is actually a ZIP file (you can easily verify that by renaming to .zip and opening it) containing several XML files. To parse the data, we first have to extract the contents, look up the right XML files and parse these. For the latter task, the XMLTABLE SQL function comes in very handy.</p> <p style="text-align: justify;">The following example code creates an&nbsp;<strong>XLSX_PARSER</strong>&nbsp;package. It uses the&nbsp;<strong>APEX_ZIP&nbsp;</strong>package to unpack the XLSX file and the&nbsp;<strong>XMLTABLE&nbsp;</strong>SQL function in order to parse the XML. The&nbsp;<strong>PARSE</strong>&nbsp;function is implemented as a table function which returns the first 50 columns (&quot;A&quot; to &quot;AX&quot;). If you need more columns, you can easily extend the code accordingly; the upper limit is 1000 columns.</p> create <b>or</b> replace <b>package</b> <span style="background-color: #ffffff">xlsx_parser</span> <b>is</b> <i>-- we currently support 50 columns - but this can easily be increased. Just increase the columns in the</i> <i>-- record definition and add corresponing lines into the package body</i> <b>type</b> <span style="background-color: #ffffff">xlsx_row_t</span> <b>is</b> <b>record</b>( <span style="background-color: #ffffff">line#</span> <b>number</b><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col01</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col02</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col03</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col04</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col05</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col06</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col07</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col08</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col09</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col10</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col11</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col12</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col13</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col14</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col15</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col16</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col17</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col18</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col19</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col20</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col21</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col22</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col23</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col24</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col25</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col26</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col27</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col28</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col29</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col30</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col31</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col32</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col33</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col34</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col35</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col36</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col37</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col38</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col39</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col40</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col41</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col42</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col43</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col44</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col45</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col46</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col47</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col48</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col49</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col50</span> <b>varchar2</b>(4000))<span style="background-color: #ffffff">;</span> <b>type</b> <span style="background-color: #ffffff">xlsx_tab_t</span> <b>is</b> <b>table</b> <b>of</b> <span style="background-color: #ffffff">xlsx_row_t</span><span style="background-color: #ffffff">;</span> <i>--==================================================================================================================</i> <i>-- table function parses the XLSX file and returns the first 15 columns.</i> <i>-- pass either the XLSX blob directly or reference a name in the APEX_APPLICATION_TEMP_FILES table.</i> <i>--</i> <i>-- p_xlsx_name - NAME column of the APEX_APPLICATION_TEMP_FILES table</i> <i>-- p_xlsx_content - XLSX as a BLOB</i> <i>-- p_worksheet_name - Worksheet to extract</i> <i>-- </i> <i>-- usage:</i> <i>--</i> <i>-- select * from table( </i> <i>-- xlsx_parser.parse( </i> <i>-- p_xlsx_name =&gt; :P1_XLSX_FILE, </i> <i>-- p_worksheet_name =&gt; :P1_WORKSHEET_NAME ) );</i> <i>--</i> <b>function</b> <span style="background-color: #ffffff">parse</span>( <span style="background-color: #ffffff">p_xlsx_name</span> <b>in</b> <b>varchar2</b> default null<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_xlsx_content</span> <b>in</b> <b>blob</b> default null<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_worksheet_name</span> <b>in</b> <b>varchar2</b> default &#39;sheet1&#39;<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_max_rows</span> <b>in</b> <b>number</b> default 1000000 ) <b>return</b> <span style="background-color: #ffffff">xlsx_tab_t</span> <b>pipelined</b><span style="background-color: #ffffff">;</span> <i>--==================================================================================================================</i> <i>-- table function to list the available worksheets in an XLSX file</i> <i>--</i> <i>-- p_xlsx_name - NAME column of the APEX_APPLICATION_TEMP_FILES table</i> <i>-- p_xlsx_content - XLSX as a BLOB</i> <i>-- </i> <i>-- usage:</i> <i>--</i> <i>-- select * from table( </i> <i>-- xlsx_parser.get_worksheets( </i> <i>-- p_xlsx_name =&gt; :P1_XLSX_FILE ) );</i> <i>--</i> <b>function</b> <span style="background-color: #ffffff">get_worksheets</span>( <span style="background-color: #ffffff">p_xlsx_content</span> <b>in</b> <b>blob</b> default null<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_xlsx_name</span> <b>in</b> <b>varchar2</b> default null ) <b>return</b> <span style="background-color: #ffffff">apex_t_varchar2</span> <b>pipelined</b><span style="background-color: #ffffff">;</span> <b>end</b> <span style="background-color: #ffffff">xlsx_parser</span><span style="background-color: #ffffff">;</span> <b>/</b> <span style="background-color: #ffffff">sho</span> <span style="background-color: #ffffff">err</span> create <b>or</b> replace <b>package</b> <b>body</b> <span style="background-color: #ffffff">xlsx_parser</span> <b>is</b> <span style="background-color: #ffffff">g_worksheets_path_prefix</span> <b>constant</b> <b>varchar2</b>(14) <b>:=</b> &#39;xl/worksheets/&#39;<span style="background-color: #ffffff">;</span> <i>--==================================================================================================================</i> <b>procedure</b> <span style="background-color: #ffffff">get_blob_content</span>( <span style="background-color: #ffffff">p_xlsx_name</span> <b>in</b> <b>varchar2</b><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_xlsx_content</span> <b>in</b> <b>out</b> <b>nocopy</b> <b>blob</b> ) <b>is</b> <b>begin</b> <b>if</b> <span style="background-color: #ffffff">p_xlsx_name</span> <b>is</b> not null <b>then</b> select <span style="background-color: #ffffff">blob_content</span> into <span style="background-color: #ffffff">p_xlsx_content</span> from <span style="background-color: #ffffff">apex_application_temp_files</span> where <b>name</b> <b>=</b> <span style="background-color: #ffffff">p_xlsx_name</span><span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <b>exception</b> <b>when</b> no_data_found <b>then</b> null<span style="background-color: #ffffff">;</span> <b>end</b> <span style="background-color: #ffffff">get_blob_content</span><span style="background-color: #ffffff">;</span> <i>--==================================================================================================================</i> <b>function</b> <span style="background-color: #ffffff">extract_worksheet</span>( <span style="background-color: #ffffff">p_xlsx</span> <b>in</b> <b>blob</b><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_worksheet_name</span> <b>in</b> <b>varchar2</b> ) <b>return</b> <b>blob</b> <b>is</b> <span style="background-color: #ffffff">l_worksheet</span> <b>blob</b><span style="background-color: #ffffff">;</span> <b>begin</b> <b>if</b> <span style="background-color: #ffffff">p_xlsx</span> <b>is</b> null <b>or</b> <span style="background-color: #ffffff">p_worksheet_name</span> <b>is</b> null <b>then</b> <b>return</b> null<span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_worksheet</span> <b>:=</b> <span style="background-color: #ffffff">apex_zip</span>.<span style="background-color: #ffffff">get_file_content</span>( <span style="background-color: #ffffff">p_zipped_blob</span> <b>=&gt;</b> <span style="background-color: #ffffff">p_xlsx</span><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_file_name</span> <b>=&gt;</b> <span style="background-color: #ffffff">g_worksheets_path_prefix</span> <b>||</b> <span style="background-color: #ffffff">p_worksheet_name</span> <b>||</b> &#39;.xml&#39; )<span style="background-color: #ffffff">;</span> <b>if</b> <span style="background-color: #ffffff">l_worksheet</span> <b>is</b> null <b>then</b> raise_application_error(<b>-</b>20000<span style="background-color: #ffffff">,</span> &#39;WORKSHEET &quot;&#39; <b>||</b> <span style="background-color: #ffffff">p_worksheet_name</span> <b>||</b> &#39;&quot; DOES NOT EXIST&#39;)<span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <b>return</b> <span style="background-color: #ffffff">l_worksheet</span><span style="background-color: #ffffff">;</span> <b>end</b> <span style="background-color: #ffffff">extract_worksheet</span><span style="background-color: #ffffff">;</span> <i>--==================================================================================================================</i> <b>procedure</b> <span style="background-color: #ffffff">extract_shared_strings</span>( <span style="background-color: #ffffff">p_xlsx</span> <b>in</b> <b>blob</b><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_strings</span> <b>in</b> <b>out</b> <b>nocopy</b> <span style="background-color: #ffffff">wwv_flow_global</span><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">vc_arr2</span> ) <b>is</b> <span style="background-color: #ffffff">l_shared_strings</span> <b>blob</b><span style="background-color: #ffffff">;</span> <b>begin</b> <span style="background-color: #ffffff">l_shared_strings</span> <b>:=</b> <span style="background-color: #ffffff">apex_zip</span>.<span style="background-color: #ffffff">get_file_content</span>( <span style="background-color: #ffffff">p_zipped_blob</span> <b>=&gt;</b> <span style="background-color: #ffffff">p_xlsx</span><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_file_name</span> <b>=&gt;</b> &#39;xl/sharedStrings.xml&#39; )<span style="background-color: #ffffff">;</span> <b>if</b> <span style="background-color: #ffffff">l_shared_strings</span> <b>is</b> null <b>then</b> <b>return</b><span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> select <span style="background-color: #ffffff">shared_string</span> <b>bulk</b> <b>collect</b> into <span style="background-color: #ffffff">p_strings</span> from <span style="background-color: #ffffff">xmltable</span>( <span style="background-color: #ffffff">xmlnamespaces</span>( default &#39;<a href="http://schemas.openxmlformats.org/spreadsheetml/2006/main">http://schemas.openxmlformats.org/spreadsheetml/2006/main</a>&#39; )<span style="background-color: #ffffff">,</span> &#39;//si&#39; <span style="background-color: #ffffff">passing</span> <span style="background-color: #ffffff">xmltype</span><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">createxml</span>( <span style="background-color: #ffffff">l_shared_strings</span><span style="background-color: #ffffff">,</span> nls_charset_id(&#39;AL32UTF8&#39;)<span style="background-color: #ffffff">,</span> null ) <span style="background-color: #ffffff">columns</span> <span style="background-color: #ffffff">shared_string</span> <b>varchar2</b>(4000) <span style="background-color: #ffffff">path</span> &#39;t/text()&#39; )<span style="background-color: #ffffff">;</span> <b>end</b> <span style="background-color: #ffffff">extract_shared_strings</span><span style="background-color: #ffffff">;</span> <i>--==================================================================================================================</i> <b>function</b> <span style="background-color: #ffffff">convert_ref_to_col#</span>( <span style="background-color: #ffffff">p_col_ref</span> <b>in</b> <b>varchar2</b> ) <b>return</b> <b>pls_integer</b> <b>is</b> <span style="background-color: #ffffff">l_colpart</span> <b>varchar2</b>(10)<span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_linepart</span> <b>varchar2</b>(10)<span style="background-color: #ffffff">;</span> <b>begin</b> <span style="background-color: #ffffff">l_colpart</span> <b>:=</b> replace(translate(<span style="background-color: #ffffff">p_col_ref</span><span style="background-color: #ffffff">,</span>&#39;1234567890&#39;<span style="background-color: #ffffff">,</span>&#39;__________&#39;)<span style="background-color: #ffffff">,</span> &#39;_&#39;)<span style="background-color: #ffffff">;</span> <b>if</b> length( <span style="background-color: #ffffff">l_colpart</span> ) <b>=</b> 1 <b>then</b> <b>return</b> ascii( <span style="background-color: #ffffff">l_colpart</span> ) <b>-</b> 64<span style="background-color: #ffffff">;</span> <b>else</b> <b>return</b> ( ascii( substr( <span style="background-color: #ffffff">l_colpart</span><span style="background-color: #ffffff">,</span> 1<span style="background-color: #ffffff">,</span> 1 ) ) <b>-</b> 64 ) <b>*</b> 26 <b>+</b> ( ascii( substr( <span style="background-color: #ffffff">l_colpart</span><span style="background-color: #ffffff">,</span> 2<span style="background-color: #ffffff">,</span> 1 ) ) <b>-</b> 64 )<span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <b>end</b> <span style="background-color: #ffffff">convert_ref_to_col#</span><span style="background-color: #ffffff">;</span> <i>--==================================================================================================================</i> <b>function</b> <span style="background-color: #ffffff">parse</span>( <span style="background-color: #ffffff">p_xlsx_name</span> <b>in</b> <b>varchar2</b> default null<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_xlsx_content</span> <b>in</b> <b>blob</b> default null<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_worksheet_name</span> <b>in</b> <b>varchar2</b> default &#39;sheet1&#39;<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_max_rows</span> <b>in</b> <b>number</b> default 1000000 ) <b>return</b> <span style="background-color: #ffffff">xlsx_tab_t</span> <b>pipelined</b> <b>is</b> <span style="background-color: #ffffff">l_worksheet</span> <b>blob</b><span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_xlsx_content</span> <b>blob</b><span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_shared_strings</span> <span style="background-color: #ffffff">wwv_flow_global</span>.<span style="background-color: #ffffff">vc_arr2</span><span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_parsed_row</span> <span style="background-color: #ffffff">xlsx_row_t</span><span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_first_row</span> <b>boolean</b> <b>:=</b> true<span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_value</span> <b>varchar2</b>(32767)<span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_line#</span> <b>pls_integer</b> <b>:=</b> 1<span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_real_col#</span> <b>pls_integer</b><span style="background-color: #ffffff">;</span> <b>begin</b> <b>if</b> <span style="background-color: #ffffff">p_xlsx_content</span> <b>is</b> null <b>then</b> <span style="background-color: #ffffff">get_blob_content</span>( <span style="background-color: #ffffff">p_xlsx_name</span><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">l_xlsx_content</span> )<span style="background-color: #ffffff">;</span> <b>else</b> <span style="background-color: #ffffff">l_xlsx_content</span> <b>:=</b> <span style="background-color: #ffffff">p_xlsx_content</span><span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <b>if</b> <span style="background-color: #ffffff">l_xlsx_content</span> <b>is</b> null <b>then</b> <b>return</b><span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_worksheet</span> <b>:=</b> <span style="background-color: #ffffff">extract_worksheet</span>( <span style="background-color: #ffffff">p_xlsx</span> <b>=&gt;</b> <span style="background-color: #ffffff">l_xlsx_content</span><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_worksheet_name</span> <b>=&gt;</b> <span style="background-color: #ffffff">p_worksheet_name</span> )<span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">extract_shared_strings</span>( <span style="background-color: #ffffff">p_xlsx</span> <b>=&gt;</b> <span style="background-color: #ffffff">l_xlsx_content</span><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_strings</span> <b>=&gt;</b> <span style="background-color: #ffffff">l_shared_strings</span> )<span style="background-color: #ffffff">;</span> <i>-- the actual XML parsing starts here</i> <b>for</b> <span style="background-color: #ffffff">i</span> <b>in</b> ( select <span style="background-color: #ffffff">r</span><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">xlsx_row</span><span style="background-color: #ffffff">,</span> <b>c</b><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">xlsx_col#</span><span style="background-color: #ffffff">,</span> <b>c</b><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">xlsx_col</span><span style="background-color: #ffffff">,</span> <b>c</b><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">xlsx_col_type</span><span style="background-color: #ffffff">,</span> <b>c</b><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">xlsx_val</span> from <span style="background-color: #ffffff">xmltable</span>( <span style="background-color: #ffffff">xmlnamespaces</span>( default &#39;<a href="http://schemas.openxmlformats.org/spreadsheetml/2006/main">http://schemas.openxmlformats.org/spreadsheetml/2006/main</a>&#39; )<span style="background-color: #ffffff">,</span> &#39;//row&#39; <span style="background-color: #ffffff">passing</span> <span style="background-color: #ffffff">xmltype</span><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">createxml</span>( <span style="background-color: #ffffff">l_worksheet</span><span style="background-color: #ffffff">,</span> nls_charset_id(&#39;AL32UTF8&#39;)<span style="background-color: #ffffff">,</span> null ) <span style="background-color: #ffffff">columns</span> <span style="background-color: #ffffff">xlsx_row</span> <b>number</b> <span style="background-color: #ffffff">path</span> &#39;@r&#39;<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">xlsx_cols</span> <span style="background-color: #ffffff">xmltype</span> <span style="background-color: #ffffff">path</span> &#39;.&#39; ) <span style="background-color: #ffffff">r</span><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">xmltable</span> ( <span style="background-color: #ffffff">xmlnamespaces</span>( default &#39;<a href="http://schemas.openxmlformats.org/spreadsheetml/2006/main">http://schemas.openxmlformats.org/spreadsheetml/2006/main</a>&#39; )<span style="background-color: #ffffff">,</span> &#39;//c&#39; <span style="background-color: #ffffff">passing</span> <span style="background-color: #ffffff">r</span><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">xlsx_cols</span> <span style="background-color: #ffffff">columns</span> <span style="background-color: #ffffff">xlsx_col#</span> <b>for</b> <span style="background-color: #ffffff">ordinality</span><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">xlsx_col</span> <b>varchar2</b>(15) <span style="background-color: #ffffff">path</span> &#39;@r&#39;<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">xlsx_col_type</span> <b>varchar2</b>(15) <span style="background-color: #ffffff">path</span> &#39;@t&#39;<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">xlsx_val</span> <b>varchar2</b>(4000) <span style="background-color: #ffffff">path</span> &#39;v/text()&#39; ) <b>c</b> where <span style="background-color: #ffffff">p_max_rows</span> <b>is</b> null <b>or</b> <span style="background-color: #ffffff">r</span><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">xlsx_row</span> <b>&lt;=</b> <span style="background-color: #ffffff">p_max_rows</span> ) <b>loop</b> <b>if</b> <span style="background-color: #ffffff">i</span>.<span style="background-color: #ffffff">xlsx_col#</span> <b>=</b> 1 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">line#</span> <b>:=</b> <span style="background-color: #ffffff">l_line#</span><span style="background-color: #ffffff">;</span> <b>if</b> not <span style="background-color: #ffffff">l_first_row</span> <b>then</b> <span style="background-color: #ffffff">pipe</span> row( <span style="background-color: #ffffff">l_parsed_row</span> )<span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_line#</span> <b>:=</b> <span style="background-color: #ffffff">l_line#</span> <b>+</b> 1<span style="background-color: #ffffff">;</span> <b>else</b> <span style="background-color: #ffffff">l_first_row</span> <b>:=</b> false<span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <b>if</b> <span style="background-color: #ffffff">i</span>.<span style="background-color: #ffffff">xlsx_col_type</span> <b>=</b> &#39;s&#39; <b>then</b> <b>if</b> <span style="background-color: #ffffff">l_shared_strings</span>.exists( <span style="background-color: #ffffff">i</span><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">xlsx_val</span> <b>+</b> 1) <b>then</b> <span style="background-color: #ffffff">l_value</span> <b>:=</b> <span style="background-color: #ffffff">l_shared_strings</span>( <span style="background-color: #ffffff">i</span><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">xlsx_val</span> <b>+</b> 1)<span style="background-color: #ffffff">;</span> <b>else</b> <span style="background-color: #ffffff">l_value</span> <b>:=</b> &#39;[Data Error: N/A]&#39; <span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <b>else</b> <span style="background-color: #ffffff">l_value</span> <b>:=</b> <span style="background-color: #ffffff">i</span>.<span style="background-color: #ffffff">xlsx_val</span><span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <b>pragma</b> <span style="background-color: #ffffff">inline</span>( <span style="background-color: #ffffff">convert_ref_to_col#</span><span style="background-color: #ffffff">,</span> &#39;YES&#39; )<span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_real_col#</span> <b>:=</b> <span style="background-color: #ffffff">convert_ref_to_col#</span>( <span style="background-color: #ffffff">i</span><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">xlsx_col</span> )<span style="background-color: #ffffff">;</span> <i>-- we currently support 50 columns - but this can easily be increased. Just add additional lines</i> <i>-- as follows:</i> <i>-- when l_real_col# = {nn} then l_parsed_row.col{nn} := l_value;</i> <b>case</b> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 1 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col01</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 2 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col02</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 3 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col03</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 4 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col04</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 5 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col05</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 6 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col06</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 7 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col07</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 8 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col08</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 9 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col09</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 10 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col10</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 11 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col11</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 12 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col12</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 13 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col13</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 14 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col14</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 15 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col15</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 16 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col16</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 17 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col17</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 18 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col18</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 19 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col19</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 20 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col20</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 21 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col21</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 22 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col22</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 23 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col23</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 24 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col24</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 25 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col25</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 26 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col26</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 27 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col27</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 28 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col28</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 29 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col29</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 30 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col30</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 31 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col31</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 32 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col32</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 33 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col33</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 34 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col34</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 35 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col35</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 36 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col36</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 37 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col37</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 38 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col38</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 39 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col39</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 40 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col40</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 41 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col41</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 42 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col42</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 43 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col43</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 44 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col44</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 45 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col45</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 46 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col46</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 47 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col47</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 48 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col48</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 49 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col49</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 50 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col50</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>else</b> null<span style="background-color: #ffffff">;</span> <b>end case</b><span style="background-color: #ffffff">;</span> <b>end loop</b><span style="background-color: #ffffff">;</span> <b>return</b><span style="background-color: #ffffff">;</span> <b>end</b> <span style="background-color: #ffffff">parse</span><span style="background-color: #ffffff">;</span> <i>--==================================================================================================================</i> <b>function</b> <span style="background-color: #ffffff">get_worksheets</span>( <span style="background-color: #ffffff">p_xlsx_content</span> <b>in</b> <b>blob</b> default null<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_xlsx_name</span> <b>in</b> <b>varchar2</b> default null ) <b>return</b> <span style="background-color: #ffffff">apex_t_varchar2</span> <b>pipelined</b> <b>is</b> <span style="background-color: #ffffff">l_zip_files</span> <span style="background-color: #ffffff">apex_zip</span>.<span style="background-color: #ffffff">t_files</span><span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_xlsx_content</span> <b>blob</b><span style="background-color: #ffffff">;</span> <b>begin</b> <b>if</b> <span style="background-color: #ffffff">p_xlsx_content</span> <b>is</b> null <b>then</b> <span style="background-color: #ffffff">get_blob_content</span>( <span style="background-color: #ffffff">p_xlsx_name</span><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">l_xlsx_content</span> )<span style="background-color: #ffffff">;</span> <b>else</b> <span style="background-color: #ffffff">l_xlsx_content</span> <b>:=</b> <span style="background-color: #ffffff">p_xlsx_content</span><span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_zip_files</span> <b>:=</b> <span style="background-color: #ffffff">apex_zip</span>.<span style="background-color: #ffffff">get_files</span>( <span style="background-color: #ffffff">p_zipped_blob</span> <b>=&gt;</b> <span style="background-color: #ffffff">l_xlsx_content</span> )<span style="background-color: #ffffff">;</span> <b>for</b> <span style="background-color: #ffffff">i</span> <b>in</b> 1 .. <span style="background-color: #ffffff">l_zip_files</span>.count <b>loop</b> <b>if</b> substr( <span style="background-color: #ffffff">l_zip_files</span>( <span style="background-color: #ffffff">i</span> )<span style="background-color: #ffffff">,</span> 1<span style="background-color: #ffffff">,</span> length( <span style="background-color: #ffffff">g_worksheets_path_prefix</span> ) ) <b>=</b> <span style="background-color: #ffffff">g_worksheets_path_prefix</span> <b>then</b> <span style="background-color: #ffffff">pipe</span> row( rtrim( substr( <span style="background-color: #ffffff">l_zip_files</span> ( <span style="background-color: #ffffff">i</span> )<span style="background-color: #ffffff">,</span> length( <span style="background-color: #ffffff">g_worksheets_path_prefix</span> ) <b>+</b> 1 )<span style="background-color: #ffffff">,</span> &#39;.xml&#39; ) )<span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <b>end loop</b><span style="background-color: #ffffff">;</span> <b>return</b><span style="background-color: #ffffff">;</span> <b>end</b> <span style="background-color: #ffffff">get_worksheets</span><span style="background-color: #ffffff">;</span> <b>end</b> <span style="background-color: #ffffff">xlsx_parser</span><span style="background-color: #ffffff">;</span> <b>/</b> <span style="background-color: #ffffff">sho</span> <span style="background-color: #ffffff">err</span> <p>The package provides the following functions:</p> FUNCTION GET_WORKSHEETS RETURNS APEX_T_VARCHAR2 Argument Name Type In/Out Default? ------------------------------ ----------------------- ------ -------- P_XLSX_CONTENT BLOB IN DEFAULT P_XLSX_NAME VARCHAR2 IN DEFAULT FUNCTION PARSE RETURNS XLSX_TAB_T Argument Name Type In/Out Default? ------------------------------ ----------------------- ------ -------- P_XLSX_NAME VARCHAR2 IN DEFAULT P_XLSX_CONTENT BLOB IN DEFAULT P_WORKSHEET_NAME VARCHAR2 IN DEFAULT P_MAX_ROWS NUMBER IN DEFAULT <p style="text-align: justify;">You can pass either the XLSX content as a BLOB or the name of an uploaded file. In the latter case, the package will look up the file name in the <strong>APEX_APPLICATION_TEMP_FILES</strong> table. A typical call sequence is as follows:</p> <ol> <li>Look up the worksheets contained in the XSLX file with <strong>XLSX_PARSER.GET_WORKSHEETS</strong></li> <li>Retrieve the Worksheet data with <strong>XLSX_PARSER.PARSE</strong>.</li> </ol> <p style="text-align: justify;">Let&#39;s try this out. Create an APEX application with an empty page, then add the following elements to that page.</p> <ul> <li>Add a Region of <strong>Static HTML</strong> type.</li> <li>Add a File Browse item named&nbsp;<strong>PX_XLSX_FILE</strong>. Choose <strong>Table APEX_APPLICATION_TEMP_FILES</strong> as the <strong>Storage Type</strong> and keep the files until the <strong>End Of Session</strong>.</li> <li>Add a Button to Upload the file. Choose <strong>Submit Page</strong> as the button action.</li> </ul> <p>Your page should now look as follows:</p> <p style="text-align: justify;"><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/30de8b5b211810c90b9a43e256252def/bildschirmfoto_2018_08_03_um_12_32_03.png" style="width: 2430px; height: 502px;" />You can already upload a file, but nothing will happen. Next, we&#39;ll want to show a select list to pick one of the worksheets contained in the XLSX file.&nbsp;</p> <ul> <li>Add a Select List item named <strong>PX_WORKSHEET</strong>.&nbsp;</li> <li>Use <strong>SQL Query</strong> as the <strong>List Of Values Type</strong> and provide the following SQL query: select column_value d, column_value r from table( xlsx_parser.get_worksheets( p_xlsx_name =&gt; :PX_XLSX_FILE ) ) </li> <li>Set <strong>Display</strong> <strong>Extra Values</strong> to <strong>No</strong>, <strong>Display Null Value</strong> to <strong>Yes</strong> and use<strong> - Choose - </strong>as the <strong>Null Display Value</strong>.</li> <li>Finally add a <em>Server-Side condition</em> to only display the select list when the <strong>PX_XLSX_FILE</strong> item <strong>IS NOT NULL</strong> (when a file has actually been uploaded)</li> </ul> <p>Now run your page again. After you have uploaded an XSLX file, your page should look as follows:</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/d8d1219ecb52e7503376417aa693370b/bildschirmfoto_2018_08_03_um_12_39_38.png" style="width: 2436px; height: 650px;" /></p> <p>So we can now pick a worksheet. So far, so good. Time to actually do the job and extract data from the XLSX file. For now, we just want to display the data as a classic report. So create a Classic Report region and use the following SQL Query.</p> select * from table( xlsx_parser.parse( p_xlsx_name =&gt; :PX_XLSX_FILE, p_worksheet_name =&gt; :PX_WORKSHEET ) ); <p>Add the <strong>PX_WORKSHEET</strong> item to the Classic Reports <strong>Page Items to Submit</strong> attribute. Then add a&nbsp;<strong>Dynamic Action</strong>&nbsp;in order to refresh the report when a worksheet has been chosen in the Select List item.</p> <ul> <li>The dynamic action should fire on the Change event of the <strong>PX_WORKSHEET</strong> item</li> <li>As the <strong>TRUE</strong> action, choose <strong>Refresh</strong> of the Classic Report region you just have created.</li> </ul> <p>You then should be able to do the following steps:</p> <ol> <li>Run the page and upload an XLSX file<br /> <img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/eab664ea4148db79c86336f2bc08f1a7/bildschirmfoto_2018_08_03_um_12_55_33.png" style="width: 1318px; height: 720px;" /></li> <li>Pick a worksheet from the select list<br /> <img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/b0b386c0301744b09522f49102969871/bildschirmfoto_2018_08_03_um_12_55_40.png" style="width: 1316px; height: 640px;" /></li> <li>The Classic Report refreshes and shows the first 50 columns of worksheet data&nbsp;<br /> <img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/01bd9065ec0d322c3b8528d031e2a4c1/bildschirmfoto_2018_08_03_um_12_55_55.png" style="width: 1324px; height: 812px;" /></li> </ol> <p>And that&#39;s it ... the nice thing is that there are no limits to process the worksheet data ...</p> <ul> <li>You can simply create a table ... <b>create</b> table worksheet_data as <b>select</b> col02 as first_name, col03 as last_name, col05 as country from table( xlsx_parser.parse( p_xlsx_name =&gt; :PX_XLSX_FILE, p_worksheet_name =&gt; :PX_WORKSHEET ) ); </li> <li>You can apply a few transformations ... <b>insert</b> into worksheet_data( <b>select</b> cast( col02 as <b>varchar2</b>(200) ) as first_name, cast( col03 as <b>varchar2</b>(200) ) as last_name, case col04 when &#39;Female&#39; then &#39;F&#39; when &#39;Male&#39; then &#39;M&#39; end as gender, cast( col05 as <b>varchar2</b>(200) ) as country, to_number( to_char( sysdate, &#39;YYYY&#39;) ) - to_number( col06 ) as birth_year from table( xlsx_parser.parse( p_xlsx_name =&gt; :PX_XLSX_FILE, p_worksheet_name =&gt; :PX_WORKSHEET ) ) where line# != 1) </li> <li>You can also create a DBMS_SCHEDULER job to push the task into the background. Note that this job does not have access to APEX session state - so you need to store the BLOB into your own table, then.</li> </ul> <p>Try the sample code out - once the table function returns data, there are no limits for further processing any more. You can do with the data whatever you want: from just displaying over loading into a table to executing complex processing in the background: Everything is possible.</p> Carsten Czarski https://blogs.oracle.com/apex/easy-xlsx-parser%3A-just-with-sql-and-plsql Fri Aug 03 2018 10:52:06 GMT-0400 (EDT) Easy XLSX Parser: Just with SQL and PL/SQL https://blogs.oracle.com/apex/easy-xlsx-parser%3A-just-with-sql-and-plsql <p style="text-align: justify;">Uploading XLSX files is a very common requirement these days. Application Express at this time only supports uploading CSV files out of the box. The community provides quite a few blog postings and also plug-ins; most of these store the data into a collection, which makes it hard to parse an XLSX outside of an APEX context, e.g. in the background using a scheduler job.</p> <p style="text-align: justify;">This blog posting shows a method to parse XLSX files with only SQL and PL/SQL. The actual work will be done by a table function, thus no collections and no APEX session is required. Since a table function returns rows and columns, one can easily insert the results into a table, apply some transformation logic, push it into the background with a scheduler job or just display.</p> <p style="text-align: justify;">The XLSX format is based on XML: an XSLX file is actually a ZIP file (you can easily verify that by renaming to .zip and opening it) containing several XML files. To parse the data, we first have to extract the contents, look up the right XML files and parse these. For the latter task, the XMLTABLE SQL function comes in very handy.</p> <p style="text-align: justify;">The following example code creates an&nbsp;<strong>XLSX_PARSER</strong>&nbsp;package. It uses the&nbsp;<strong>APEX_ZIP&nbsp;</strong>package to unpack the XLSX file and the&nbsp;<strong>XMLTABLE&nbsp;</strong>SQL function in order to parse the XML. The&nbsp;<strong>PARSE</strong>&nbsp;function is implemented as a table function which returns the first 50 columns (&quot;A&quot; to &quot;AX&quot;). If you need more columns, you can easily extend the code accordingly; the upper limit is 1000 columns.</p> create <b>or</b> replace <b>package</b> <span style="background-color: #ffffff">xlsx_parser</span> <b>is</b> <i>-- we currently support 50 columns - but this can easily be increased. Just increase the columns in the</i> <i>-- record definition and add corresponing lines into the package body</i> <b>type</b> <span style="background-color: #ffffff">xlsx_row_t</span> <b>is</b> <b>record</b>( <span style="background-color: #ffffff">line#</span> <b>number</b><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col01</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col02</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col03</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col04</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col05</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col06</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col07</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col08</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col09</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col10</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col11</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col12</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col13</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col14</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col15</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col16</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col17</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col18</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col19</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col20</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col21</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col22</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col23</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col24</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col25</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col26</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col27</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col28</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col29</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col30</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col31</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col32</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col33</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col34</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col35</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col36</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col37</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col38</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col39</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col40</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col41</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col42</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col43</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col44</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col45</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col46</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col47</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col48</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col49</span> <b>varchar2</b>(4000)<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">col50</span> <b>varchar2</b>(4000))<span style="background-color: #ffffff">;</span> <b>type</b> <span style="background-color: #ffffff">xlsx_tab_t</span> <b>is</b> <b>table</b> <b>of</b> <span style="background-color: #ffffff">xlsx_row_t</span><span style="background-color: #ffffff">;</span> <i>--==================================================================================================================</i> <i>-- table function parses the XLSX file and returns the first 15 columns.</i> <i>-- pass either the XLSX blob directly or reference a name in the APEX_APPLICATION_TEMP_FILES table.</i> <i>--</i> <i>-- p_xlsx_name - NAME column of the APEX_APPLICATION_TEMP_FILES table</i> <i>-- p_xlsx_content - XLSX as a BLOB</i> <i>-- p_worksheet_name - Worksheet to extract</i> <i>-- </i> <i>-- usage:</i> <i>--</i> <i>-- select * from table( </i> <i>-- xlsx_parser.parse( </i> <i>-- p_xlsx_name =&gt; :P1_XLSX_FILE, </i> <i>-- p_worksheet_name =&gt; :P1_WORKSHEET_NAME ) );</i> <i>--</i> <b>function</b> <span style="background-color: #ffffff">parse</span>( <span style="background-color: #ffffff">p_xlsx_name</span> <b>in</b> <b>varchar2</b> default null<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_xlsx_content</span> <b>in</b> <b>blob</b> default null<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_worksheet_name</span> <b>in</b> <b>varchar2</b> default &#39;sheet1&#39;<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_max_rows</span> <b>in</b> <b>number</b> default 1000000 ) <b>return</b> <span style="background-color: #ffffff">xlsx_tab_t</span> <b>pipelined</b><span style="background-color: #ffffff">;</span> <i>--==================================================================================================================</i> <i>-- table function to list the available worksheets in an XLSX file</i> <i>--</i> <i>-- p_xlsx_name - NAME column of the APEX_APPLICATION_TEMP_FILES table</i> <i>-- p_xlsx_content - XLSX as a BLOB</i> <i>-- </i> <i>-- usage:</i> <i>--</i> <i>-- select * from table( </i> <i>-- xlsx_parser.get_worksheets( </i> <i>-- p_xlsx_name =&gt; :P1_XLSX_FILE ) );</i> <i>--</i> <b>function</b> <span style="background-color: #ffffff">get_worksheets</span>( <span style="background-color: #ffffff">p_xlsx_content</span> <b>in</b> <b>blob</b> default null<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_xlsx_name</span> <b>in</b> <b>varchar2</b> default null ) <b>return</b> <span style="background-color: #ffffff">apex_t_varchar2</span> <b>pipelined</b><span style="background-color: #ffffff">;</span> <b>end</b> <span style="background-color: #ffffff">xlsx_parser</span><span style="background-color: #ffffff">;</span> <b>/</b> <span style="background-color: #ffffff">sho</span> <span style="background-color: #ffffff">err</span> create <b>or</b> replace <b>package</b> <b>body</b> <span style="background-color: #ffffff">xlsx_parser</span> <b>is</b> <span style="background-color: #ffffff">g_worksheets_path_prefix</span> <b>constant</b> <b>varchar2</b>(14) <b>:=</b> &#39;xl/worksheets/&#39;<span style="background-color: #ffffff">;</span> <i>--==================================================================================================================</i> <b>procedure</b> <span style="background-color: #ffffff">get_blob_content</span>( <span style="background-color: #ffffff">p_xlsx_name</span> <b>in</b> <b>varchar2</b><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_xlsx_content</span> <b>in</b> <b>out</b> <b>nocopy</b> <b>blob</b> ) <b>is</b> <b>begin</b> <b>if</b> <span style="background-color: #ffffff">p_xlsx_name</span> <b>is</b> not null <b>then</b> select <span style="background-color: #ffffff">blob_content</span> into <span style="background-color: #ffffff">p_xlsx_content</span> from <span style="background-color: #ffffff">apex_application_temp_files</span> where <b>name</b> <b>=</b> <span style="background-color: #ffffff">p_xlsx_name</span><span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <b>exception</b> <b>when</b> no_data_found <b>then</b> null<span style="background-color: #ffffff">;</span> <b>end</b> <span style="background-color: #ffffff">get_blob_content</span><span style="background-color: #ffffff">;</span> <i>--==================================================================================================================</i> <b>function</b> <span style="background-color: #ffffff">extract_worksheet</span>( <span style="background-color: #ffffff">p_xlsx</span> <b>in</b> <b>blob</b><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_worksheet_name</span> <b>in</b> <b>varchar2</b> ) <b>return</b> <b>blob</b> <b>is</b> <span style="background-color: #ffffff">l_worksheet</span> <b>blob</b><span style="background-color: #ffffff">;</span> <b>begin</b> <b>if</b> <span style="background-color: #ffffff">p_xlsx</span> <b>is</b> null <b>or</b> <span style="background-color: #ffffff">p_worksheet_name</span> <b>is</b> null <b>then</b> <b>return</b> null<span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_worksheet</span> <b>:=</b> <span style="background-color: #ffffff">apex_zip</span>.<span style="background-color: #ffffff">get_file_content</span>( <span style="background-color: #ffffff">p_zipped_blob</span> <b>=&gt;</b> <span style="background-color: #ffffff">p_xlsx</span><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_file_name</span> <b>=&gt;</b> <span style="background-color: #ffffff">g_worksheets_path_prefix</span> <b>||</b> <span style="background-color: #ffffff">p_worksheet_name</span> <b>||</b> &#39;.xml&#39; )<span style="background-color: #ffffff">;</span> <b>if</b> <span style="background-color: #ffffff">l_worksheet</span> <b>is</b> null <b>then</b> raise_application_error(<b>-</b>20000<span style="background-color: #ffffff">,</span> &#39;WORKSHEET &quot;&#39; <b>||</b> <span style="background-color: #ffffff">p_worksheet_name</span> <b>||</b> &#39;&quot; DOES NOT EXIST&#39;)<span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <b>return</b> <span style="background-color: #ffffff">l_worksheet</span><span style="background-color: #ffffff">;</span> <b>end</b> <span style="background-color: #ffffff">extract_worksheet</span><span style="background-color: #ffffff">;</span> <i>--==================================================================================================================</i> <b>procedure</b> <span style="background-color: #ffffff">extract_shared_strings</span>( <span style="background-color: #ffffff">p_xlsx</span> <b>in</b> <b>blob</b><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_strings</span> <b>in</b> <b>out</b> <b>nocopy</b> <span style="background-color: #ffffff">wwv_flow_global</span><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">vc_arr2</span> ) <b>is</b> <span style="background-color: #ffffff">l_shared_strings</span> <b>blob</b><span style="background-color: #ffffff">;</span> <b>begin</b> <span style="background-color: #ffffff">l_shared_strings</span> <b>:=</b> <span style="background-color: #ffffff">apex_zip</span>.<span style="background-color: #ffffff">get_file_content</span>( <span style="background-color: #ffffff">p_zipped_blob</span> <b>=&gt;</b> <span style="background-color: #ffffff">p_xlsx</span><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_file_name</span> <b>=&gt;</b> &#39;xl/sharedStrings.xml&#39; )<span style="background-color: #ffffff">;</span> <b>if</b> <span style="background-color: #ffffff">l_shared_strings</span> <b>is</b> null <b>then</b> <b>return</b><span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> select <span style="background-color: #ffffff">shared_string</span> <b>bulk</b> <b>collect</b> into <span style="background-color: #ffffff">p_strings</span> from <span style="background-color: #ffffff">xmltable</span>( <span style="background-color: #ffffff">xmlnamespaces</span>( default &#39;<a href="http://schemas.openxmlformats.org/spreadsheetml/2006/main">http://schemas.openxmlformats.org/spreadsheetml/2006/main</a>&#39; )<span style="background-color: #ffffff">,</span> &#39;//si&#39; <span style="background-color: #ffffff">passing</span> <span style="background-color: #ffffff">xmltype</span><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">createxml</span>( <span style="background-color: #ffffff">l_shared_strings</span><span style="background-color: #ffffff">,</span> nls_charset_id(&#39;AL32UTF8&#39;)<span style="background-color: #ffffff">,</span> null ) <span style="background-color: #ffffff">columns</span> <span style="background-color: #ffffff">shared_string</span> <b>varchar2</b>(4000) <span style="background-color: #ffffff">path</span> &#39;t/text()&#39; )<span style="background-color: #ffffff">;</span> <b>end</b> <span style="background-color: #ffffff">extract_shared_strings</span><span style="background-color: #ffffff">;</span> <i>--==================================================================================================================</i> <b>function</b> <span style="background-color: #ffffff">convert_ref_to_col#</span>( <span style="background-color: #ffffff">p_col_ref</span> <b>in</b> <b>varchar2</b> ) <b>return</b> <b>pls_integer</b> <b>is</b> <span style="background-color: #ffffff">l_colpart</span> <b>varchar2</b>(10)<span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_linepart</span> <b>varchar2</b>(10)<span style="background-color: #ffffff">;</span> <b>begin</b> <span style="background-color: #ffffff">l_colpart</span> <b>:=</b> replace(translate(<span style="background-color: #ffffff">p_col_ref</span><span style="background-color: #ffffff">,</span>&#39;1234567890&#39;<span style="background-color: #ffffff">,</span>&#39;__________&#39;)<span style="background-color: #ffffff">,</span> &#39;_&#39;)<span style="background-color: #ffffff">;</span> <b>if</b> length( <span style="background-color: #ffffff">l_colpart</span> ) <b>=</b> 1 <b>then</b> <b>return</b> ascii( <span style="background-color: #ffffff">l_colpart</span> ) <b>-</b> 64<span style="background-color: #ffffff">;</span> <b>else</b> <b>return</b> ( ascii( substr( <span style="background-color: #ffffff">l_colpart</span><span style="background-color: #ffffff">,</span> 1<span style="background-color: #ffffff">,</span> 1 ) ) <b>-</b> 64 ) <b>*</b> 26 <b>+</b> ( ascii( substr( <span style="background-color: #ffffff">l_colpart</span><span style="background-color: #ffffff">,</span> 2<span style="background-color: #ffffff">,</span> 1 ) ) <b>-</b> 64 )<span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <b>end</b> <span style="background-color: #ffffff">convert_ref_to_col#</span><span style="background-color: #ffffff">;</span> <i>--==================================================================================================================</i> <b>function</b> <span style="background-color: #ffffff">parse</span>( <span style="background-color: #ffffff">p_xlsx_name</span> <b>in</b> <b>varchar2</b> default null<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_xlsx_content</span> <b>in</b> <b>blob</b> default null<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_worksheet_name</span> <b>in</b> <b>varchar2</b> default &#39;sheet1&#39;<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_max_rows</span> <b>in</b> <b>number</b> default 1000000 ) <b>return</b> <span style="background-color: #ffffff">xlsx_tab_t</span> <b>pipelined</b> <b>is</b> <span style="background-color: #ffffff">l_worksheet</span> <b>blob</b><span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_xlsx_content</span> <b>blob</b><span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_shared_strings</span> <span style="background-color: #ffffff">wwv_flow_global</span>.<span style="background-color: #ffffff">vc_arr2</span><span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_parsed_row</span> <span style="background-color: #ffffff">xlsx_row_t</span><span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_first_row</span> <b>boolean</b> <b>:=</b> true<span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_value</span> <b>varchar2</b>(32767)<span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_line#</span> <b>pls_integer</b> <b>:=</b> 1<span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_real_col#</span> <b>pls_integer</b><span style="background-color: #ffffff">;</span> <b>begin</b> <b>if</b> <span style="background-color: #ffffff">p_xlsx_content</span> <b>is</b> null <b>then</b> <span style="background-color: #ffffff">get_blob_content</span>( <span style="background-color: #ffffff">p_xlsx_name</span><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">l_xlsx_content</span> )<span style="background-color: #ffffff">;</span> <b>else</b> <span style="background-color: #ffffff">l_xlsx_content</span> <b>:=</b> <span style="background-color: #ffffff">p_xlsx_content</span><span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <b>if</b> <span style="background-color: #ffffff">l_xlsx_content</span> <b>is</b> null <b>then</b> <b>return</b><span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_worksheet</span> <b>:=</b> <span style="background-color: #ffffff">extract_worksheet</span>( <span style="background-color: #ffffff">p_xlsx</span> <b>=&gt;</b> <span style="background-color: #ffffff">l_xlsx_content</span><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_worksheet_name</span> <b>=&gt;</b> <span style="background-color: #ffffff">p_worksheet_name</span> )<span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">extract_shared_strings</span>( <span style="background-color: #ffffff">p_xlsx</span> <b>=&gt;</b> <span style="background-color: #ffffff">l_xlsx_content</span><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_strings</span> <b>=&gt;</b> <span style="background-color: #ffffff">l_shared_strings</span> )<span style="background-color: #ffffff">;</span> <i>-- the actual XML parsing starts here</i> <b>for</b> <span style="background-color: #ffffff">i</span> <b>in</b> ( select <span style="background-color: #ffffff">r</span><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">xlsx_row</span><span style="background-color: #ffffff">,</span> <b>c</b><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">xlsx_col#</span><span style="background-color: #ffffff">,</span> <b>c</b><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">xlsx_col</span><span style="background-color: #ffffff">,</span> <b>c</b><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">xlsx_col_type</span><span style="background-color: #ffffff">,</span> <b>c</b><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">xlsx_val</span> from <span style="background-color: #ffffff">xmltable</span>( <span style="background-color: #ffffff">xmlnamespaces</span>( default &#39;<a href="http://schemas.openxmlformats.org/spreadsheetml/2006/main">http://schemas.openxmlformats.org/spreadsheetml/2006/main</a>&#39; )<span style="background-color: #ffffff">,</span> &#39;//row&#39; <span style="background-color: #ffffff">passing</span> <span style="background-color: #ffffff">xmltype</span><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">createxml</span>( <span style="background-color: #ffffff">l_worksheet</span><span style="background-color: #ffffff">,</span> nls_charset_id(&#39;AL32UTF8&#39;)<span style="background-color: #ffffff">,</span> null ) <span style="background-color: #ffffff">columns</span> <span style="background-color: #ffffff">xlsx_row</span> <b>number</b> <span style="background-color: #ffffff">path</span> &#39;@r&#39;<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">xlsx_cols</span> <span style="background-color: #ffffff">xmltype</span> <span style="background-color: #ffffff">path</span> &#39;.&#39; ) <span style="background-color: #ffffff">r</span><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">xmltable</span> ( <span style="background-color: #ffffff">xmlnamespaces</span>( default &#39;<a href="http://schemas.openxmlformats.org/spreadsheetml/2006/main">http://schemas.openxmlformats.org/spreadsheetml/2006/main</a>&#39; )<span style="background-color: #ffffff">,</span> &#39;//c&#39; <span style="background-color: #ffffff">passing</span> <span style="background-color: #ffffff">r</span><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">xlsx_cols</span> <span style="background-color: #ffffff">columns</span> <span style="background-color: #ffffff">xlsx_col#</span> <b>for</b> <span style="background-color: #ffffff">ordinality</span><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">xlsx_col</span> <b>varchar2</b>(15) <span style="background-color: #ffffff">path</span> &#39;@r&#39;<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">xlsx_col_type</span> <b>varchar2</b>(15) <span style="background-color: #ffffff">path</span> &#39;@t&#39;<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">xlsx_val</span> <b>varchar2</b>(4000) <span style="background-color: #ffffff">path</span> &#39;v/text()&#39; ) <b>c</b> where <span style="background-color: #ffffff">p_max_rows</span> <b>is</b> null <b>or</b> <span style="background-color: #ffffff">r</span><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">xlsx_row</span> <b>&lt;=</b> <span style="background-color: #ffffff">p_max_rows</span> ) <b>loop</b> <b>if</b> <span style="background-color: #ffffff">i</span>.<span style="background-color: #ffffff">xlsx_col#</span> <b>=</b> 1 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">line#</span> <b>:=</b> <span style="background-color: #ffffff">l_line#</span><span style="background-color: #ffffff">;</span> <b>if</b> not <span style="background-color: #ffffff">l_first_row</span> <b>then</b> <span style="background-color: #ffffff">pipe</span> row( <span style="background-color: #ffffff">l_parsed_row</span> )<span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_line#</span> <b>:=</b> <span style="background-color: #ffffff">l_line#</span> <b>+</b> 1<span style="background-color: #ffffff">;</span> <b>else</b> <span style="background-color: #ffffff">l_first_row</span> <b>:=</b> false<span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <b>if</b> <span style="background-color: #ffffff">i</span>.<span style="background-color: #ffffff">xlsx_col_type</span> <b>=</b> &#39;s&#39; <b>then</b> <b>if</b> <span style="background-color: #ffffff">l_shared_strings</span>.exists( <span style="background-color: #ffffff">i</span><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">xlsx_val</span> <b>+</b> 1) <b>then</b> <span style="background-color: #ffffff">l_value</span> <b>:=</b> <span style="background-color: #ffffff">l_shared_strings</span>( <span style="background-color: #ffffff">i</span><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">xlsx_val</span> <b>+</b> 1)<span style="background-color: #ffffff">;</span> <b>else</b> <span style="background-color: #ffffff">l_value</span> <b>:=</b> &#39;[Data Error: N/A]&#39; <span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <b>else</b> <span style="background-color: #ffffff">l_value</span> <b>:=</b> <span style="background-color: #ffffff">i</span>.<span style="background-color: #ffffff">xlsx_val</span><span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <b>pragma</b> <span style="background-color: #ffffff">inline</span>( <span style="background-color: #ffffff">convert_ref_to_col#</span><span style="background-color: #ffffff">,</span> &#39;YES&#39; )<span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_real_col#</span> <b>:=</b> <span style="background-color: #ffffff">convert_ref_to_col#</span>( <span style="background-color: #ffffff">i</span><span style="background-color: #ffffff">.</span><span style="background-color: #ffffff">xlsx_col</span> )<span style="background-color: #ffffff">;</span> <i>-- we currently support 50 columns - but this can easily be increased. Just add additional lines</i> <i>-- as follows:</i> <i>-- when l_real_col# = {nn} then l_parsed_row.col{nn} := l_value;</i> <b>case</b> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 1 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col01</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 2 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col02</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 3 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col03</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 4 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col04</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 5 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col05</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 6 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col06</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 7 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col07</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 8 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col08</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 9 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col09</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 10 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col10</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 11 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col11</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 12 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col12</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 13 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col13</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 14 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col14</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 15 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col15</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 16 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col16</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 17 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col17</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 18 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col18</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 19 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col19</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 20 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col20</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 21 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col21</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 22 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col22</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 23 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col23</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 24 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col24</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 25 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col25</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 26 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col26</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 27 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col27</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 28 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col28</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 29 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col29</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 30 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col30</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 31 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col31</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 32 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col32</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 33 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col33</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 34 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col34</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 35 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col35</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 36 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col36</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 37 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col37</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 38 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col38</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 39 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col39</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 40 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col40</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 41 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col41</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 42 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col42</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 43 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col43</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 44 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col44</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 45 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col45</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 46 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col46</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 47 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col47</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 48 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col48</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 49 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col49</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>when</b> <span style="background-color: #ffffff">l_real_col#</span> <b>=</b> 50 <b>then</b> <span style="background-color: #ffffff">l_parsed_row</span>.<span style="background-color: #ffffff">col50</span> <b>:=</b> <span style="background-color: #ffffff">l_value</span><span style="background-color: #ffffff">;</span> <b>else</b> null<span style="background-color: #ffffff">;</span> <b>end case</b><span style="background-color: #ffffff">;</span> <b>end loop</b><span style="background-color: #ffffff">;</span> <b>return</b><span style="background-color: #ffffff">;</span> <b>end</b> <span style="background-color: #ffffff">parse</span><span style="background-color: #ffffff">;</span> <i>--==================================================================================================================</i> <b>function</b> <span style="background-color: #ffffff">get_worksheets</span>( <span style="background-color: #ffffff">p_xlsx_content</span> <b>in</b> <b>blob</b> default null<span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">p_xlsx_name</span> <b>in</b> <b>varchar2</b> default null ) <b>return</b> <span style="background-color: #ffffff">apex_t_varchar2</span> <b>pipelined</b> <b>is</b> <span style="background-color: #ffffff">l_zip_files</span> <span style="background-color: #ffffff">apex_zip</span>.<span style="background-color: #ffffff">t_files</span><span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_xlsx_content</span> <b>blob</b><span style="background-color: #ffffff">;</span> <b>begin</b> <b>if</b> <span style="background-color: #ffffff">p_xlsx_content</span> <b>is</b> null <b>then</b> <span style="background-color: #ffffff">get_blob_content</span>( <span style="background-color: #ffffff">p_xlsx_name</span><span style="background-color: #ffffff">,</span> <span style="background-color: #ffffff">l_xlsx_content</span> )<span style="background-color: #ffffff">;</span> <b>else</b> <span style="background-color: #ffffff">l_xlsx_content</span> <b>:=</b> <span style="background-color: #ffffff">p_xlsx_content</span><span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <span style="background-color: #ffffff">l_zip_files</span> <b>:=</b> <span style="background-color: #ffffff">apex_zip</span>.<span style="background-color: #ffffff">get_files</span>( <span style="background-color: #ffffff">p_zipped_blob</span> <b>=&gt;</b> <span style="background-color: #ffffff">l_xlsx_content</span> )<span style="background-color: #ffffff">;</span> <b>for</b> <span style="background-color: #ffffff">i</span> <b>in</b> 1 .. <span style="background-color: #ffffff">l_zip_files</span>.count <b>loop</b> <b>if</b> substr( <span style="background-color: #ffffff">l_zip_files</span>( <span style="background-color: #ffffff">i</span> )<span style="background-color: #ffffff">,</span> 1<span style="background-color: #ffffff">,</span> length( <span style="background-color: #ffffff">g_worksheets_path_prefix</span> ) ) <b>=</b> <span style="background-color: #ffffff">g_worksheets_path_prefix</span> <b>then</b> <span style="background-color: #ffffff">pipe</span> row( rtrim( substr( <span style="background-color: #ffffff">l_zip_files</span> ( <span style="background-color: #ffffff">i</span> )<span style="background-color: #ffffff">,</span> length( <span style="background-color: #ffffff">g_worksheets_path_prefix</span> ) <b>+</b> 1 )<span style="background-color: #ffffff">,</span> &#39;.xml&#39; ) )<span style="background-color: #ffffff">;</span> <b>end if</b><span style="background-color: #ffffff">;</span> <b>end loop</b><span style="background-color: #ffffff">;</span> <b>return</b><span style="background-color: #ffffff">;</span> <b>end</b> <span style="background-color: #ffffff">get_worksheets</span><span style="background-color: #ffffff">;</span> <b>end</b> <span style="background-color: #ffffff">xlsx_parser</span><span style="background-color: #ffffff">;</span> <b>/</b> <span style="background-color: #ffffff">sho</span> <span style="background-color: #ffffff">err</span> <p>The package provides the following functions:</p> FUNCTION GET_WORKSHEETS RETURNS APEX_T_VARCHAR2 Argument Name Type In/Out Default? ------------------------------ ----------------------- ------ -------- P_XLSX_CONTENT BLOB IN DEFAULT P_XLSX_NAME VARCHAR2 IN DEFAULT FUNCTION PARSE RETURNS XLSX_TAB_T Argument Name Type In/Out Default? ------------------------------ ----------------------- ------ -------- P_XLSX_NAME VARCHAR2 IN DEFAULT P_XLSX_CONTENT BLOB IN DEFAULT P_WORKSHEET_NAME VARCHAR2 IN DEFAULT P_MAX_ROWS NUMBER IN DEFAULT <p style="text-align: justify;">You can pass either the XLSX content as a BLOB or the name of an uploaded file. In the latter case, the package will look up the file name in the <strong>APEX_APPLICATION_TEMP_FILES</strong> table. A typical call sequence is as follows:</p> <ol> <li>Look up the worksheets contained in the XSLX file with <strong>XLSX_PARSER.GET_WORKSHEETS</strong></li> <li>Retrieve the Worksheet data with <strong>XLSX_PARSER.PARSE</strong>.</li> </ol> <p style="text-align: justify;">Let&#39;s try this out. Create an APEX application with an empty page, then add the following elements to that page.</p> <ul> <li>Add a Region of <strong>Static HTML</strong> type.</li> <li>Add a File Browse item named&nbsp;<strong>PX_XLSX_FILE</strong>. Choose <strong>Table APEX_APPLICATION_TEMP_FILES</strong> as the <strong>Storage Type</strong> and keep the files until the <strong>End Of Session</strong>.</li> <li>Add a Button to Upload the file. Choose <strong>Submit Page</strong> as the button action.</li> </ul> <p>Your page should now look as follows:</p> <p style="text-align: justify;"><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/30de8b5b211810c90b9a43e256252def/bildschirmfoto_2018_08_03_um_12_32_03.png" style="width: 2430px; height: 502px;" />You can already upload a file, but nothing will happen. Next, we&#39;ll want to show a select list to pick one of the worksheets contained in the XLSX file.&nbsp;</p> <ul> <li>Add a Select List item named <strong>PX_WORKSHEET</strong>.&nbsp;</li> <li>Use <strong>SQL Query</strong> as the <strong>List Of Values Type</strong> and provide the following SQL query: select column_value d, column_value r from table( xlsx_parser.get_worksheets( p_xlsx_name =&gt; :PX_XLSX_FILE ) ) </li> <li>Set <strong>Display</strong> <strong>Extra Values</strong> to <strong>No</strong>, <strong>Display Null Value</strong> to <strong>Yes</strong> and use<strong> - Choose - </strong>as the <strong>Null Display Value</strong>.</li> <li>Finally add a <em>Server-Side condition</em> to only display the select list when the <strong>PX_XLSX_FILE</strong> item <strong>IS NOT NULL</strong> (when a file has actually been uploaded)</li> </ul> <p>Now run your page again. After you have uploaded an XSLX file, your page should look as follows:</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/d8d1219ecb52e7503376417aa693370b/bildschirmfoto_2018_08_03_um_12_39_38.png" style="width: 2436px; height: 650px;" /></p> <p>So we can now pick a worksheet. So far, so good. Time to actually do the job and extract data from the XLSX file. For now, we just want to display the data as a classic report. So create a Classic Report region and use the following SQL Query.</p> select * from table( xlsx_parser.parse( p_xlsx_name =&gt; :PX_XLSX_FILE, p_worksheet_name =&gt; :PX_WORKSHEET ) ); <p>Add the <strong>PX_WORKSHEET</strong> item to the Classic Reports <strong>Page Items to Submit</strong> attribute. Then add a&nbsp;<strong>Dynamic Action</strong>&nbsp;in order to refresh the report when a worksheet has been chosen in the Select List item.</p> <ul> <li>The dynamic action should fire on the Change event of the <strong>PX_WORKSHEET</strong> item</li> <li>As the <strong>TRUE</strong> action, choose <strong>Refresh</strong> of the Classic Report region you just have created.</li> </ul> <p>You then should be able to do the following steps:</p> <ol> <li>Run the page and upload an XLSX file<br /> <img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/eab664ea4148db79c86336f2bc08f1a7/bildschirmfoto_2018_08_03_um_12_55_33.png" style="width: 1318px; height: 720px;" /></li> <li>Pick a worksheet from the select list<br /> <img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/b0b386c0301744b09522f49102969871/bildschirmfoto_2018_08_03_um_12_55_40.png" style="width: 1316px; height: 640px;" /></li> <li>The Classic Report refreshes and shows the first 50 columns of worksheet data&nbsp;<br /> <img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/01bd9065ec0d322c3b8528d031e2a4c1/bildschirmfoto_2018_08_03_um_12_55_55.png" style="width: 1324px; height: 812px;" /></li> </ol> <p>And that&#39;s it ... the nice thing is that there are no limits to process the worksheet data ...</p> <ul> <li>You can simply create a table ... <b>create</b> table worksheet_data as <b>select</b> col02 as first_name, col03 as last_name, col05 as country from table( xlsx_parser.parse( p_xlsx_name =&gt; :PX_XLSX_FILE, p_worksheet_name =&gt; :PX_WORKSHEET ) ); </li> <li>You can apply a few transformations ... <b>insert</b> into worksheet_data( <b>select</b> cast( col02 as <b>varchar2</b>(200) ) as first_name, cast( col03 as <b>varchar2</b>(200) ) as last_name, case col04 when &#39;Female&#39; then &#39;F&#39; when &#39;Male&#39; then &#39;M&#39; end as gender, cast( col05 as <b>varchar2</b>(200) ) as country, to_number( to_char( sysdate, &#39;YYYY&#39;) ) - to_number( col06 ) as birth_year from table( xlsx_parser.parse( p_xlsx_name =&gt; :PX_XLSX_FILE, p_worksheet_name =&gt; :PX_WORKSHEET ) ) where line# != 1) </li> <li>You can also create a DBMS_SCHEDULER job to push the task into the background. Note that this job does not have access to APEX session state - so you need to store the BLOB into your own table, then.</li> </ul> <p>Try the sample code out - once the table function returns data, there are no limits for further processing any more. You can do with the data whatever you want: from just displaying over loading into a table to executing complex processing in the background: Everything is possible.</p> Carsten Czarski https://blogs.oracle.com/apex/easy-xlsx-parser%3A-just-with-sql-and-plsql Fri Aug 03 2018 10:52:06 GMT-0400 (EDT) XLSX Upload leicht gemacht: Ein einfacher XLSX-Parser. https://blogs.oracle.com/apexcommunity_deutsch/xlsx-upload-leicht-gemacht%3A-ein-einfacher-xlsx-parser <p style="text-align: justify;">Die Anforderung, XLSX-Dateien in eine APEX-Anwendung hochzuladen, ist eigentlich recht g&auml;ngig. Aus dem Stand unterst&uuml;tzt APEX aber nur den Upload von CSV-Dateien. Aus der Entwicklergemeinde sind Blog-Postings und auch Plug-Ins verf&uuml;gbar - viele davon arbeiten im Hintergrund allerdings mit APEX Collections, sind daher an eine APEX-Session gebunden und lassen sich nur schwer au&szlig;erhalb einer APEX-Anwendung (bspw. in einem Scheduler-Job) nutzen.</p> <p style="text-align: justify;">Dieses Blog-Posting stellt einen XLSX-Parser vor, der nur mit SQL und PL/SQL arbeitet. Die Implementierung steckt in einer Table-Function, welche die aus der XLSX-Datei extrahierten Daten in Form von Zeilen und Spalten zur&uuml;ckgibt. Es werden keine Daten tempor&auml;r gespeichert - Collections werden nicht ben&ouml;tigt.</p> <p style="text-align: justify;">Das XLSX-Format ist technisch ein ZIP-Archiv (das kann man auch ausprobieren: einfach von .xlsx in .zip umbenennen und &ouml;ffnen). In diesem ZIP-Archiv befinden sich XML-Dateien mit den Daten aus dem Excel-Workbook. Um die Daten zu extrahieren, muss man also die richtigen XML-Dateien finden und diese parsen. Und zum XML-Parsing bringt die Datenbank gl&uuml;cklicherweise alles mit, was gebraucht wird.</p> <p style="text-align: justify;">Der folgende Code erzeugt also das PL/SQL Package&nbsp;<strong>XLSX_PARSER</strong>. In diesem wird das <strong>APEX_ZIP </strong>Package verwendet, um das ZIP-Archiv zu entpacken, und die SQL Funktion&nbsp;<strong>XMLTABLE</strong>, um das XML zu parsen und die Daten zu extrahieren. Der REST ist ein wenig PL/SQL-Logik, um die aus dem XML extrahierten Daten korrekt als Zeilen und Spalten zur&uuml;ckzugeben.</p> <p style="text-align: justify;">Der Code, so wie er hier vorliegt, unterst&uuml;tzt die Extraktion von bis zu 50 Spalten aus, XLSX-Dateien mit mehreren Worksheets werden unterst&uuml;tzt. Wenn mehr als 50 Spalten gebraucht werden, so kann der Code sehr leicht erweitert werden - es sind Kommentare enthalten, die auf die zu &auml;ndernden Stellen hinweisen: So muss die RECORD-Definition zu Beginn des Package und ein Code-Abschnitt in der PARSE Funktion erweitert werden. Das obere Limit sind 1.000 Spalten.</p> <p style="text-align: justify;">Damit genug der Vorrede - hier ist der Code:</p> create <b>or</b> replace <b>package</b> xlsx_parser <b>is</b> <i>-- we currently support 50 columns - but this can easily be increased. Just increase the columns in the</i> <i>-- record definition and add corresponing lines into the package body</i> <b>type</b> xlsx_row_t <b>is</b> <b>record</b>( line# <b>number</b>, col01 <b>varchar2</b>(4000), col02 <b>varchar2</b>(4000), col03 <b>varchar2</b>(4000), col04 <b>varchar2</b>(4000), col05 <b>varchar2</b>(4000), col06 <b>varchar2</b>(4000), col07 <b>varchar2</b>(4000), col08 <b>varchar2</b>(4000), col09 <b>varchar2</b>(4000), col10 <b>varchar2</b>(4000), col11 <b>varchar2</b>(4000), col12 <b>varchar2</b>(4000), col13 <b>varchar2</b>(4000), col14 <b>varchar2</b>(4000), col15 <b>varchar2</b>(4000), col16 <b>varchar2</b>(4000), col17 <b>varchar2</b>(4000), col18 <b>varchar2</b>(4000), col19 <b>varchar2</b>(4000), col20 <b>varchar2</b>(4000), col21 <b>varchar2</b>(4000), col22 <b>varchar2</b>(4000), col23 <b>varchar2</b>(4000), col24 <b>varchar2</b>(4000), col25 <b>varchar2</b>(4000), col26 <b>varchar2</b>(4000), col27 <b>varchar2</b>(4000), col28 <b>varchar2</b>(4000), col29 <b>varchar2</b>(4000), col30 <b>varchar2</b>(4000), col31 <b>varchar2</b>(4000), col32 <b>varchar2</b>(4000), col33 <b>varchar2</b>(4000), col34 <b>varchar2</b>(4000), col35 <b>varchar2</b>(4000), col36 <b>varchar2</b>(4000), col37 <b>varchar2</b>(4000), col38 <b>varchar2</b>(4000), col39 <b>varchar2</b>(4000), col40 <b>varchar2</b>(4000), col41 <b>varchar2</b>(4000), col42 <b>varchar2</b>(4000), col43 <b>varchar2</b>(4000), col44 <b>varchar2</b>(4000), col45 <b>varchar2</b>(4000), col46 <b>varchar2</b>(4000), col47 <b>varchar2</b>(4000), col48 <b>varchar2</b>(4000), col49 <b>varchar2</b>(4000), col50 <b>varchar2</b>(4000)); <b>type</b> xlsx_tab_t <b>is</b> <b>table</b> <b>of</b> xlsx_row_t; <i>--==================================================================================================================</i> <i>-- table function parses the XLSX file and returns the first 15 columns.</i> <i>-- pass either the XLSX blob directly or reference a name in the APEX_APPLICATION_TEMP_FILES table.</i> <i>--</i> <i>-- p_xlsx_name - NAME column of the APEX_APPLICATION_TEMP_FILES table</i> <i>-- p_xlsx_content - XLSX as a BLOB</i> <i>-- p_worksheet_name - Worksheet to extract</i> <i>-- </i> <i>-- usage:</i> <i>--</i> <i>-- select * from table( </i> <i>-- xlsx_parser.parse( </i> <i>-- p_xlsx_name =&gt; :P1_XLSX_FILE, </i> <i>-- p_worksheet_name =&gt; :P1_WORKSHEET_NAME ) );</i> <i>--</i> <b>function</b> parse( p_xlsx_name <b>in</b> <b>varchar2</b> default null, p_xlsx_content <b>in</b> <b>blob</b> default null, p_worksheet_name <b>in</b> <b>varchar2</b> default &#39;sheet1&#39;, p_max_rows <b>in</b> <b>number</b> default 1000000 ) <b>return</b> xlsx_tab_t <b>pipelined</b>; <i>--==================================================================================================================</i> <i>-- table function to list the available worksheets in an XLSX file</i> <i>--</i> <i>-- p_xlsx_name - NAME column of the APEX_APPLICATION_TEMP_FILES table</i> <i>-- p_xlsx_content - XLSX as a BLOB</i> <i>-- </i> <i>-- usage:</i> <i>--</i> <i>-- select * from table( </i> <i>-- xlsx_parser.get_worksheets( </i> <i>-- p_xlsx_name =&gt; :P1_XLSX_FILE ) );</i> <i>--</i> <b>function</b> get_worksheets( p_xlsx_content <b>in</b> <b>blob</b> default null, p_xlsx_name <b>in</b> <b>varchar2</b> default null ) <b>return</b> apex_t_varchar2 <b>pipelined</b>; <b>end</b> xlsx_parser; <b>/</b> sho err create <b>or</b> replace <b>package</b> <b>body</b> xlsx_parser <b>is</b> g_worksheets_path_prefix <b>constant</b> <b>varchar2</b>(14) <b>:=</b> &#39;xl/worksheets/&#39;; <i>--==================================================================================================================</i> <b>procedure</b> get_blob_content( p_xlsx_name <b>in</b> <b>varchar2</b>, p_xlsx_content <b>in</b> <b>out</b> <b>nocopy</b> <b>blob</b> ) <b>is</b> <b>begin</b> <b>if</b> p_xlsx_name <b>is</b> not null <b>then</b> select blob_content into p_xlsx_content from apex_application_temp_files where <b>name</b> <b>=</b> p_xlsx_name; <b>end if</b>; <b>exception</b> <b>when</b> no_data_found <b>then</b> null; <b>end</b> get_blob_content; <i>--==================================================================================================================</i> <b>function</b> extract_worksheet( p_xlsx <b>in</b> <b>blob</b>, p_worksheet_name <b>in</b> <b>varchar2</b> ) <b>return</b> <b>blob</b> <b>is</b> l_worksheet <b>blob</b>; <b>begin</b> <b>if</b> p_xlsx <b>is</b> null <b>or</b> p_worksheet_name <b>is</b> null <b>then</b> <b>return</b> null; <b>end if</b>; l_worksheet <b>:=</b> apex_zip.get_file_content( p_zipped_blob <b>=&gt;</b> p_xlsx, p_file_name <b>=&gt;</b> g_worksheets_path_prefix <b>||</b> p_worksheet_name <b>||</b> &#39;.xml&#39; ); <b>if</b> l_worksheet <b>is</b> null <b>then</b> raise_application_error(<b>-</b>20000, &#39;WORKSHEET &quot;&#39; <b>||</b> p_worksheet_name <b>||</b> &#39;&quot; DOES NOT EXIST&#39;); <b>end if</b>; <b>return</b> l_worksheet; <b>end</b> extract_worksheet; <i>--==================================================================================================================</i> <b>procedure</b> extract_shared_strings( p_xlsx <b>in</b> <b>blob</b>, p_strings <b>in</b> <b>out</b> <b>nocopy</b> wwv_flow_global.vc_arr2 ) <b>is</b> l_shared_strings <b>blob</b>; <b>begin</b> l_shared_strings <b>:=</b> apex_zip.get_file_content( p_zipped_blob <b>=&gt;</b> p_xlsx, p_file_name <b>=&gt;</b> &#39;xl/sharedStrings.xml&#39; ); <b>if</b> l_shared_strings <b>is</b> null <b>then</b> <b>return</b>; <b>end if</b>; select shared_string <b>bulk</b> <b>collect</b> into p_strings from xmltable( xmlnamespaces( default &#39;<a href="http://schemas.openxmlformats.org/spreadsheetml/2006/main">http://schemas.openxmlformats.org/spreadsheetml/2006/main</a>&#39; ), &#39;//si&#39; passing xmltype.createxml( l_shared_strings, nls_charset_id(&#39;AL32UTF8&#39;), null ) columns shared_string <b>varchar2</b>(4000) path &#39;t/text()&#39; ); <b>end</b> extract_shared_strings; <i>--==================================================================================================================</i> <b>function</b> convert_ref_to_col#( p_col_ref <b>in</b> <b>varchar2</b> ) <b>return</b> <b>pls_integer</b> <b>is</b> l_colpart <b>varchar2</b>(10); l_linepart <b>varchar2</b>(10); <b>begin</b> l_colpart <b>:=</b> replace(translate(p_col_ref,&#39;1234567890&#39;,&#39;__________&#39;), &#39;_&#39;); <b>if</b> length( l_colpart ) <b>=</b> 1 <b>then</b> <b>return</b> ascii( l_colpart ) <b>-</b> 64; <b>else</b> <b>return</b> ( ascii( substr( l_colpart, 1, 1 ) ) <b>-</b> 64 ) <b>*</b> 26 <b>+</b> ( ascii( substr( l_colpart, 2, 1 ) ) <b>-</b> 64 ); <b>end if</b>; <b>end</b> convert_ref_to_col#; <i>--==================================================================================================================</i> <b>function</b> parse( p_xlsx_name <b>in</b> <b>varchar2</b> default null, p_xlsx_content <b>in</b> <b>blob</b> default null, p_worksheet_name <b>in</b> <b>varchar2</b> default &#39;sheet1&#39;, p_max_rows <b>in</b> <b>number</b> default 1000000 ) <b>return</b> xlsx_tab_t <b>pipelined</b> <b>is</b> l_worksheet <b>blob</b>; l_xlsx_content <b>blob</b>; l_shared_strings wwv_flow_global.vc_arr2; l_parsed_row xlsx_row_t; l_first_row <b>boolean</b> <b>:=</b> true; l_value <b>varchar2</b>(32767); l_line# <b>pls_integer</b> <b>:=</b> 1; l_real_col# <b>pls_integer</b>; <b>begin</b> <b>if</b> p_xlsx_content <b>is</b> null <b>then</b> get_blob_content( p_xlsx_name, l_xlsx_content ); <b>else</b> l_xlsx_content <b>:=</b> p_xlsx_content; <b>end if</b>; <b>if</b> l_xlsx_content <b>is</b> null <b>then</b> <b>return</b>; <b>end if</b>; l_worksheet <b>:=</b> extract_worksheet( p_xlsx <b>=&gt;</b> l_xlsx_content, p_worksheet_name <b>=&gt;</b> p_worksheet_name ); extract_shared_strings( p_xlsx <b>=&gt;</b> l_xlsx_content, p_strings <b>=&gt;</b> l_shared_strings ); <i>-- the actual XML parsing starts here</i> <b>for</b> i <b>in</b> ( select r.xlsx_row, <b>c</b>.xlsx_col#, <b>c</b>.xlsx_col, <b>c</b>.xlsx_col_type, <b>c</b>.xlsx_val from xmltable( xmlnamespaces( default &#39;<a href="http://schemas.openxmlformats.org/spreadsheetml/2006/main">http://schemas.openxmlformats.org/spreadsheetml/2006/main</a>&#39; ), &#39;//row&#39; passing xmltype.createxml( l_worksheet, nls_charset_id(&#39;AL32UTF8&#39;), null ) columns xlsx_row <b>number</b> path &#39;@r&#39;, xlsx_cols xmltype path &#39;.&#39; ) r, xmltable ( xmlnamespaces( default &#39;<a href="http://schemas.openxmlformats.org/spreadsheetml/2006/main">http://schemas.openxmlformats.org/spreadsheetml/2006/main</a>&#39; ), &#39;//c&#39; passing r.xlsx_cols columns xlsx_col# <b>for</b> ordinality, xlsx_col <b>varchar2</b>(15) path &#39;@r&#39;, xlsx_col_type <b>varchar2</b>(15) path &#39;@t&#39;, xlsx_val <b>varchar2</b>(4000) path &#39;v/text()&#39; ) <b>c</b> where p_max_rows <b>is</b> null <b>or</b> r.xlsx_row <b>&lt;=</b> p_max_rows ) <b>loop</b> <b>if</b> i.xlsx_col# <b>=</b> 1 <b>then</b> l_parsed_row.line# <b>:=</b> l_line#; <b>if</b> not l_first_row <b>then</b> pipe row( l_parsed_row ); l_line# <b>:=</b> l_line# <b>+</b> 1; <b>else</b> l_first_row <b>:=</b> false; <b>end if</b>; <b>end if</b>; <b>if</b> i.xlsx_col_type <b>=</b> &#39;s&#39; <b>then</b> <b>if</b> l_shared_strings.exists( i.xlsx_val <b>+</b> 1) <b>then</b> l_value <b>:=</b> l_shared_strings( i.xlsx_val <b>+</b> 1); <b>else</b> l_value <b>:=</b> &#39;[Data Error: N/A]&#39; ; <b>end if</b>; <b>else</b> l_value <b>:=</b> i.xlsx_val; <b>end if</b>; <b>pragma</b> inline( convert_ref_to_col#, &#39;YES&#39; ); l_real_col# <b>:=</b> convert_ref_to_col#( i.xlsx_col ); <i>-- we currently support 50 columns - but this can easily be increased. Just add additional lines</i> <i>-- as follows:</i> <i>-- when l_real_col# = {nn} then l_parsed_row.col{nn} := l_value;</i> <b>case</b> <b>when</b> l_real_col# <b>=</b> 1 <b>then</b> l_parsed_row.col01 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 2 <b>then</b> l_parsed_row.col02 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 3 <b>then</b> l_parsed_row.col03 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 4 <b>then</b> l_parsed_row.col04 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 5 <b>then</b> l_parsed_row.col05 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 6 <b>then</b> l_parsed_row.col06 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 7 <b>then</b> l_parsed_row.col07 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 8 <b>then</b> l_parsed_row.col08 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 9 <b>then</b> l_parsed_row.col09 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 10 <b>then</b> l_parsed_row.col10 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 11 <b>then</b> l_parsed_row.col11 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 12 <b>then</b> l_parsed_row.col12 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 13 <b>then</b> l_parsed_row.col13 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 14 <b>then</b> l_parsed_row.col14 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 15 <b>then</b> l_parsed_row.col15 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 16 <b>then</b> l_parsed_row.col16 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 17 <b>then</b> l_parsed_row.col17 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 18 <b>then</b> l_parsed_row.col18 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 19 <b>then</b> l_parsed_row.col19 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 20 <b>then</b> l_parsed_row.col20 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 21 <b>then</b> l_parsed_row.col21 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 22 <b>then</b> l_parsed_row.col22 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 23 <b>then</b> l_parsed_row.col23 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 24 <b>then</b> l_parsed_row.col24 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 25 <b>then</b> l_parsed_row.col25 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 26 <b>then</b> l_parsed_row.col26 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 27 <b>then</b> l_parsed_row.col27 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 28 <b>then</b> l_parsed_row.col28 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 29 <b>then</b> l_parsed_row.col29 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 30 <b>then</b> l_parsed_row.col30 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 31 <b>then</b> l_parsed_row.col31 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 32 <b>then</b> l_parsed_row.col32 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 33 <b>then</b> l_parsed_row.col33 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 34 <b>then</b> l_parsed_row.col34 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 35 <b>then</b> l_parsed_row.col35 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 36 <b>then</b> l_parsed_row.col36 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 37 <b>then</b> l_parsed_row.col37 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 38 <b>then</b> l_parsed_row.col38 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 39 <b>then</b> l_parsed_row.col39 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 40 <b>then</b> l_parsed_row.col40 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 41 <b>then</b> l_parsed_row.col41 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 42 <b>then</b> l_parsed_row.col42 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 43 <b>then</b> l_parsed_row.col43 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 44 <b>then</b> l_parsed_row.col44 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 45 <b>then</b> l_parsed_row.col45 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 46 <b>then</b> l_parsed_row.col46 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 47 <b>then</b> l_parsed_row.col47 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 48 <b>then</b> l_parsed_row.col48 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 49 <b>then</b> l_parsed_row.col49 <b>:=</b> l_value; <b>when</b> l_real_col# <b>=</b> 50 <b>then</b> l_parsed_row.col50 <b>:=</b> l_value; <b>else</b> null; <b>end case</b>; <b>end loop</b>; <b>return</b>; <b>end</b> parse; <i>--==================================================================================================================</i> <b>function</b> get_worksheets( p_xlsx_content <b>in</b> <b>blob</b> default null, p_xlsx_name <b>in</b> <b>varchar2</b> default null ) <b>return</b> apex_t_varchar2 <b>pipelined</b> <b>is</b> l_zip_files apex_zip.t_files; l_xlsx_content <b>blob</b>; <b>begin</b> <b>if</b> p_xlsx_content <b>is</b> null <b>then</b> get_blob_content( p_xlsx_name, l_xlsx_content ); <b>else</b> l_xlsx_content <b>:=</b> p_xlsx_content; <b>end if</b>; l_zip_files <b>:=</b> apex_zip.get_files( p_zipped_blob <b>=&gt;</b> l_xlsx_content ); <b>for</b> i <b>in</b> 1 .. l_zip_files.count <b>loop</b> <b>if</b> substr( l_zip_files( i ), 1, length( g_worksheets_path_prefix ) ) <b>=</b> g_worksheets_path_prefix <b>then</b> pipe row( rtrim( substr( l_zip_files ( i ), length( g_worksheets_path_prefix ) <b>+</b> 1 ), &#39;.xml&#39; ) ); <b>end if</b>; <b>end loop</b>; <b>return</b>; <b>end</b> get_worksheets; <b>end</b> xlsx_parser; <b>/</b> sho err <p>Nach dem Einspielen des Package stehen die folgenden Funktionen bereit:</p> FUNCTION GET_WORKSHEETS RETURNS APEX_T_VARCHAR2 Argument Name Type In/Out Default? ------------------------------ ----------------------- ------ -------- P_XLSX_CONTENT BLOB IN DEFAULT P_XLSX_NAME VARCHAR2 IN DEFAULT FUNCTION PARSE RETURNS XLSX_TAB_T Argument Name Type In/Out Default? ------------------------------ ----------------------- ------ -------- P_XLSX_NAME VARCHAR2 IN DEFAULT P_XLSX_CONTENT BLOB IN DEFAULT P_WORKSHEET_NAME VARCHAR2 IN DEFAULT P_MAX_ROWS NUMBER IN DEFAULT <p style="text-align: justify;">Die XLSX-Datei kann entweder als BLOB oder als Dateiname &uuml;bergeben werden. In letzterem Fall wird der BLOB aus der Tabelle <strong>APEX_APPLICATION_TEMP_FILES</strong> geholt - das ist n&uuml;tzlich, wenn die Datei mit einem APEX File Browse Element hochgeladen wurde. Eine typische Aufruf-Sequenz sieht wie folgt aus:</p> <ol> <li>Im XLSX vorhandene Worksheets mit <strong>XLSX_PARSER.GET_WORKSHEETS</strong> auslesen</li> <li>Die Daten eines konkreten Worksheet&nbsp; <strong>XLSX_PARSER.PARSE</strong> extrahieren.</li> </ol> <p style="text-align: justify;">Probieren Sie es gleich aus: Erstellen Sie dazu eine&nbsp;APEX-Anwendung mit einer leeren Seite. F&uuml;gen Sie dann die folgenden Komponenten hinzu.</p> <ul> <li>Eine Region vom Typ&nbsp;<strong>Static HTML.</strong></li> <li>Ein File Browse Element zum Hochladen der XLSX-Datei: &quot;PX_XLSX_FILE&quot;. Nehmen Sie&nbsp;<strong>Table APEX_APPLICATION_TEMP_FILES</strong>&nbsp;als&nbsp;<strong>Storage Type</strong>&nbsp;und behalten Sie die Dateien&nbsp;bis zum&nbsp;<strong>End Of Session</strong>.</li> <li>F&uuml;gen Sie dann noch einen Button zum Hochladen hinzu. Stellen Sie sicher, dass die <em>Button-Action</em> auf&nbsp;<strong>Submit Page</strong>&nbsp;steht.</li> </ul> <p>Die Seite sollte dann in etwa wie folgt aussehen:</p> <p style="text-align: justify;"><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/30de8b5b211810c90b9a43e256252def/bildschirmfoto_2018_08_03_um_12_32_03.png" style="width: 2430px; height: 502px;" />Sie k&ouml;nnen schon eine Datei hochladen, aber es wird dann noch nichts passieren. Als n&auml;chstes soll die Seite erweitert werden, so dass sie eine Auswahlliste enth&auml;lt, welche die in der XLSX-Datei vorhandenen&nbsp;<em>Worksheets </em>anzeigt.&nbsp;</p> <ul> <li>F&uuml;gen Sie ein Element vom Typ <strong>Select List</strong> namens&nbsp; <strong>PX_WORKSHEET</strong> hinzu.</li> <li>Nehmen Sie <strong>SQL Query</strong> als <strong>List Of Values Type</strong>&nbsp;und verwenden Sie die folgende SQL-Abfrage: select column_value d, column_value r from table( xlsx_parser.get_worksheets( p_xlsx_name =&gt; :PX_XLSX_FILE ) ) </li> <li>Stellen Sie&nbsp;<strong>Display</strong>&nbsp;<strong>Extra Values</strong>&nbsp;auf&nbsp;<strong>No</strong>,&nbsp;<strong>Display Null Value</strong>&nbsp;auf&nbsp;<strong>Yes</strong>&nbsp;und nehmen Sie<strong>&nbsp;- Choose -&nbsp;</strong>als <strong>Null Display Value</strong>.</li> <li>F&uuml;gen Sie schlie&szlig;lich eine<em>Server-Side condition</em>&nbsp;hinzu, so dass die Auswahlliste nur angezeigt wird, wenn das File Browse Element&nbsp;<strong>PX_XLSX_FILE</strong>&nbsp;einen Wert hat (<strong>IS NOT NULL</strong>).</li> </ul> <p>Starten Sie die Seite nochmal. Wenn Sie nun eine XLSX-Datei hochladen, sollte die Seite wie folgt aussehen.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/d8d1219ecb52e7503376417aa693370b/bildschirmfoto_2018_08_03_um_12_39_38.png" style="width: 2436px; height: 650px;" /></p> <p>Nun k&ouml;nnen Sie also eines der in der XLSX-Datei enthaltenen Worksheets ausw&auml;hlen. Nun ist es an der Zeit, die Daten aus dem ausgew&auml;hlten Worksheet zu extrahieren: F&uuml;r den Moment wollen wir sie einfach nur darstellen, nehmen Sie daher also einen Classic Report. Die SQL-Abfrage des Classic Report verwendet die Table-Function des XLSX-Parsers: <strong>XLSX_PARSER.PARSE</strong>.</p> select * from table( xlsx_parser.parse( p_xlsx_name =&gt; :PX_XLSX_FILE, p_worksheet_name =&gt; :PX_WORKSHEET ) ); <p>F&uuml;gen Sie das Element&nbsp;<strong>PX_WORKSHEET</strong>&nbsp;zu dem&nbsp;<strong>Page Items to Submit</strong>&nbsp;Attribut des Classic Report hinzu. Dann braucht es noch eine <strong>Dynamic Action</strong>,&nbsp;&nbsp;damit der Bericht sich aktualisiert, sobald ein Worksheet in der Auswahlliste selektiert wurde.</p> <ul> <li>Die Dynamic Action sollte ausl&ouml;sen, wenn ein <em>Change</em> Ereignis auf dem Element&nbsp;<strong>PX_WORKSHEET</strong>&nbsp;stattfindet.</li> <li>Als <strong>TRUE</strong>&nbsp;Action nehmen Sie <strong>Refresh</strong>&nbsp;und w&auml;hlen Sie die Classic Report Region aus <strong>Affected Region&nbsp;</strong>aus.</li> </ul> <p>Nun sollte Ihre Anwendungsseite den folgenden Ablauf unterst&uuml;tzen:</p> <ol> <li>Starten Sie die Seite und laden Sie ein XLSX hoch.<br /> <img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/eab664ea4148db79c86336f2bc08f1a7/bildschirmfoto_2018_08_03_um_12_55_33.png" style="width: 1318px; height: 720px;" /></li> <li>W&auml;hlen Sie ein&nbsp;<em>Worksheet</em>&nbsp;aus der Auswahlliste aus.<br /> <img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/b0b386c0301744b09522f49102969871/bildschirmfoto_2018_08_03_um_12_55_40.png" style="width: 1316px; height: 640px;" /></li> <li>Die Berichtsregion sollte sich aktualisieren und die extrahierten Daten anzeigen.<br /> <img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/01bd9065ec0d322c3b8528d031e2a4c1/bildschirmfoto_2018_08_03_um_12_55_55.png" style="width: 1324px; height: 812px;" /></li> </ol> <p>Fertig. Und das Sch&ouml;ne daran ist, dass dieser Ansatz sehr offen ist - die die Daten von der Table Function wie eine Tabelle bereitgestellt werden, k&ouml;nnen sie auch beliebig weiterverarbeitet werden ...</p> <ul> <li>Man k&ouml;nnte sie einfach in eine Tabelle kopieren ... <b>create</b> table worksheet_data as <b>select</b> col02 as first_name, col03 as last_name, col05 as country from table( xlsx_parser.parse( p_xlsx_name =&gt; :PX_XLSX_FILE, p_worksheet_name =&gt; :PX_WORKSHEET ) ); </li> <li>Einige Transformationen anwenden ... <b>insert</b> into worksheet_data( <b>select</b> cast( col02 as <b>varchar2</b>(200) ) as first_name, cast( col03 as <b>varchar2</b>(200) ) as last_name, case col04 when &#39;Female&#39; then &#39;F&#39; when &#39;Male&#39; then &#39;M&#39; end as gender, cast( col05 as <b>varchar2</b>(200) ) as country, to_number( to_char( sysdate, &#39;YYYY&#39;) ) - to_number( col06 ) as birth_year from table( xlsx_parser.parse( p_xlsx_name =&gt; :PX_XLSX_FILE, p_worksheet_name =&gt; :PX_WORKSHEET ) ) where line# != 1) </li> <li>Oder das Ganze mit einem DBMS_SCHEDULER job in den Hintergrund schicken - was bei gr&ouml;&szlig;eren XLSX-Dateien sicherlich interessant ist. Beachten Sie dabei allerdings, dass ein DBMS_SCHEDULER job in einer eigenen Datenbanksession - und unabh&auml;ngig von APEX l&auml;uft. In der Tabelle APEX_APPLICATION_TEMP_FILES wird er also nichts finden - kopieren Sie den BLOB daher vorher in eine eigene Tabelle ...</li> </ul> <p>Probieren Sie den Beispiel-Code aus! Sobald die Table Function Daten zur&uuml;ckliefert, sind Ihren M&ouml;glichkeiten keinerlei Grenzen mehr gesetzt. Und wenn Sie mehr Spalten brauchen - der Code ist sehr leicht erweiterbar.</p> Carsten Czarski https://blogs.oracle.com/apexcommunity_deutsch/xlsx-upload-leicht-gemacht%3A-ein-einfacher-xlsx-parser Fri Aug 03 2018 10:50:54 GMT-0400 (EDT) APEX Application for Managing Other APEX Application Properties in Your Workspace http://www.explorer.uk.com/apex-application-for-managing-other-apex-application-properties-in-your-workspace/ <p>As part of my presentation I gave at a couple of OUG events (see <a href="http://www.explorer.uk.com/application-support-with-apex-applications-looking-after-the-users-when-development-has-finished/" target="_blank" rel="noopener">here</a> for the blog post and video) one of things I discussed is how APEX has <strong><u>built in</u></strong> many things that can help when managing an application. I start talking about this at <a href="https://youtu.be/fNdraJqshmE?t=37m19s" target="_blank" rel="noopener">37m19s</a> in the video about how during releases the following built in things are useful for keeping users informed when supporting an APEX application, particularly during a release:</p> <ul> <li>Global notifications (to announce up-coming downtime for example)</li> <li>Application Availability Status</li> <li>Message for Unavailable Applications</li> <li>Restricted User Access</li> </ul> <p><a href="http://www.explorer.uk.com/wp-content/uploads/2018/07/APEX-Availability.png" rel="lightbox[7418]"><img class="aligncenter wp-image-7420 size-full" src="http://www.explorer.uk.com/wp-content/uploads/2018/07/APEX-Availability.png" alt="" width="801" height="545" srcset="http://www.explorer.uk.com/wp-content/uploads/2018/07/APEX-Availability.png 801w, http://www.explorer.uk.com/wp-content/uploads/2018/07/APEX-Availability-300x204.png 300w, http://www.explorer.uk.com/wp-content/uploads/2018/07/APEX-Availability-768x523.png 768w" sizes="(max-width: 801px) 100vw, 801px" /></a></p> <p>Although these functions within Application Properties are incredibly useful your ability to use them is only available if developer mode is enabled on the instance the applications are running on, the application isn’t set to ‘Run Only’ and also that the user who manages them has access to the developer dashboard. What can we do when any of these aren’t true?</p> <p>Well, as you will see demonstrated in the video, I showed a front end application developed for managing some of these properties. I have had a number of enquires about how this application works, what it queries and what API’s are used to update the properties, and the purpose of this blog post is to explain the application a little further.</p> <p>As seen in the video and below this is what the application looks like and it will show all the applications and what their properties currently are:</p> <p><a href="http://www.explorer.uk.com/wp-content/uploads/2018/07/Show-all-applications.png" rel="lightbox[7418]"><img class="aligncenter size-large wp-image-7421" src="http://www.explorer.uk.com/wp-content/uploads/2018/07/Show-all-applications-1024x240.png" alt="" width="800" height="188" srcset="http://www.explorer.uk.com/wp-content/uploads/2018/07/Show-all-applications-1024x240.png 1024w, http://www.explorer.uk.com/wp-content/uploads/2018/07/Show-all-applications-300x70.png 300w, http://www.explorer.uk.com/wp-content/uploads/2018/07/Show-all-applications-768x180.png 768w, http://www.explorer.uk.com/wp-content/uploads/2018/07/Show-all-applications.png 1499w" sizes="(max-width: 800px) 100vw, 800px" /></a></p> <p>This is just a report using a query on the wwv_flows table (which was granted to my schema), it would also be possible to use the APEX_APPLICATIONS view for this information and this is the query:</p> <p><a href="http://www.explorer.uk.com/wp-content/uploads/2018/07/APEX-Applications-Query.png" rel="lightbox[7418]"><img class="aligncenter size-full wp-image-7422" src="http://www.explorer.uk.com/wp-content/uploads/2018/07/APEX-Applications-Query.png" alt="" width="1006" height="147" srcset="http://www.explorer.uk.com/wp-content/uploads/2018/07/APEX-Applications-Query.png 1006w, http://www.explorer.uk.com/wp-content/uploads/2018/07/APEX-Applications-Query-300x44.png 300w, http://www.explorer.uk.com/wp-content/uploads/2018/07/APEX-Applications-Query-768x112.png 768w" sizes="(max-width: 1006px) 100vw, 1006px" /></a></p> <p>The edit link on the report links to a form page which populates the items with the same information from the wwv_flows table for the application selected:</p> <p><a href="http://www.explorer.uk.com/wp-content/uploads/2018/07/wwv_flows-table.png" rel="lightbox[7418]"><img class="aligncenter size-full wp-image-7423" src="http://www.explorer.uk.com/wp-content/uploads/2018/07/wwv_flows-table.png" alt="" width="715" height="374" srcset="http://www.explorer.uk.com/wp-content/uploads/2018/07/wwv_flows-table.png 715w, http://www.explorer.uk.com/wp-content/uploads/2018/07/wwv_flows-table-300x157.png 300w" sizes="(max-width: 715px) 100vw, 715px" /></a></p> <p>Once the user has completed any updates required then by using some API calls to <a href="https://docs.oracle.com/database/apex-5.1/AEAPI/APEX_UTIL.htm#AEAPI101" target="_blank" rel="noopener">apex_util</a> we can update these properties of the application but from the front end instead:</p> <p><a href="http://www.explorer.uk.com/wp-content/uploads/2018/07/Front-end-applications.png" rel="lightbox[7418]"><img class="aligncenter size-full wp-image-7424" src="http://www.explorer.uk.com/wp-content/uploads/2018/07/Front-end-applications.png" alt="" width="632" height="229" srcset="http://www.explorer.uk.com/wp-content/uploads/2018/07/Front-end-applications.png 632w, http://www.explorer.uk.com/wp-content/uploads/2018/07/Front-end-applications-300x109.png 300w" sizes="(max-width: 632px) 100vw, 632px" /></a></p> <p>You will probably want to add some exclusions to your report of applications which can be updated (The application support application itself should probably be excluded) and you will also want to set up a strictly controlled authentication scheme for the support application as what you are exposing is some pretty powerful functionality of APEX to a front end user!</p> <p>The post <a rel="nofollow" href="http://www.explorer.uk.com/apex-application-for-managing-other-apex-application-properties-in-your-workspace/">APEX Application for Managing Other APEX Application Properties in Your Workspace</a> appeared first on <a rel="nofollow" href="http://www.explorer.uk.com">Explorer | Award Winning UK Oracle Partner</a>.</p> Devon Page http://www.explorer.uk.com/?p=7418 Fri Aug 03 2018 06:05:29 GMT-0400 (EDT) 2019 Leadership Program - Now Accepting Applications https://www.odtug.com/p/bl/et/blogaid=811&source=1 Are you looking to invest in your professional development? Do you enjoy the ODTUG community and are you looking to become more involved? The ODTUG leadership program is a great way to accomplish both goals and broaden your network. ODTUG https://www.odtug.com/p/bl/et/blogaid=811&source=1 Thu Aug 02 2018 11:57:06 GMT-0400 (EDT) APEX 18.2 Statement of Direction http://www.grassroots-oracle.com/2018/08/apex-182-statement-of-direction.html I've been thinking recently it's been a while since I remember seeing a revised <a href="http://www.grassroots-oracle.com/2015/10/apex-51-revised-sod-and-apexworld.html" target="_blank">Statement of Direction,</a> and sure enough I see news of an update for 18.2.<br /><br />It was <a href="http://www.grassroots-oracle.com/2015/10/apex-51-revised-sod-and-apexworld.html" target="_blank">back in 2015</a> that I last made my own conjecture about what each statement means (without the benefit of listening to as many conference sessions) and look at some of the outcomes now!<br /><br /><ul><li>IG - well, I'm still a little late to that party, but missing out on early cuts &amp; bruises ;p</li><li>Master detail detail - I was training people last week and it occurred to me this is another feature I don't really work with, but maybe should give a go.</li><li>New charting engine - well JET is going really well! Though I'm still experiencing teething issues with the <a href="https://community.oracle.com/message/14745791" target="_blank">data densification</a>.</li></ul><br />As for APEX 18.2, we now see:<br /><br /><ul><li>Improved workspace provisioning wizard - not a big drawcard for myself, but I can see how some fresh attention in this space could be warranted.</li><li>New side-by-side master detail page type available in create page wizard - as I just noted, I need to experiment with recent master-detail development, to perhaps integrate with regular design patterns.</li><li>New dashboard page type available in create page wizard -&nbsp;Now I’m guessing this is just a wizard to help build an appropriate page – full of components already available to us, but used in an effective way. Either way, I'm interested.</li><li>Improved warnings with REST workshop to prevent loss of custom definitions - well, that sounds useful.</li><li>More comprehensive JavaScript API documentation - <a href="https://docs.oracle.com/database/apex-18.1/AEXJS/index.html" target="_blank">even more</a>? I've barely had a chance at using the new set. I hope it comes with more examples. I think I saw a glimpse of Shakeeb's /ut application the other night with SQL examples inline for classic report variations. +1 from me.</li><li>Ability to update Font APEX stylesheets and font files independent of Oracle APEX releases - <a href="http://www.grassroots-oracle.com/2017/03/font-apex-between-versions.html" target="_blank">Maxime</a> already showed us this was possible, and easy. I'm glad behaviour like this is enabled by the APEX team.&nbsp;</li><li>Installing sample datasets now enables the creation of a complete sample application - well, that sounds intriguing.</li><li>EMP / DEPT sample dataset now available in different languages - sometimes I'm grateful my first language is English, but sometimes I really wish I was natively bilingual.</li><li>Updated productivity and sample apps - seems to go without saying now, but I haven't farmed them for ideas for a while.</li></ul><div>They've always come through pretty well with these lists, plus a whole bunch of other extra stuff we find along the way.<br /><br /></div><div>After recent experiences I thought I'd add a few examples of what I'd <i>like </i>to see, no doubt forgetting/neglecting some other needs &amp; wants, includes:</div><div><ul><li>IR - support for saved IR (&amp; IG?) are still hidden away a few layers deep in a task menu. Saved IR are still inseparable from app_id. We could use some love here.</li><li>Excel2Collection - considering the efforts made in assisting Access &amp; Forms users to migrate their information to APEX, perhaps it might be wise to integrate such a simple method of transferring Excel workbook content to a table in the database.<br />The ORDS solution hung around for a while, and I find the data loading wizard somewhat clunky.&nbsp;</li><li>PWA - Vincent recently published a <a href="https://vmorneau.me/apex-pwa/" target="_blank">comprehensive guide</a> on turning APEX into a PWA. This technology is early days (certainly in my learning bubble), but I think APEX would benefit from internal support in regard to further penetrating the mobile market.</li><li>Native Super LOV - <a href="https://github.com/mennooo/orclapex-modal-lov">this one</a> from Menno is great, but surely it's time this was baked in?</li><li>Dynamic Action support for inline modals - there are a few lines of JavaScript I repeat often that I'm sure could be replaced by declarative actions</li></ul><div>Anything else? I've made wishlishs in the past (<a href="http://www.grassroots-oracle.com/2012/12/apex-5-desires.html">5.x</a>, <a href="http://www.grassroots-oracle.com/2011/12/my-apex-42-wish-list.html">4.2</a>), but looking back they seem a little mundane.</div></div> Scott Wesley tag:blogger.com,1999:blog-4818542164384221282.post-7935096621028168703 Wed Aug 01 2018 09:46:00 GMT-0400 (EDT) APEX as a PWA: The Complete Guide http://vmorneau.me/apex-pwa/ <div class="kg-post"> <h2 id="coveredfeatures">Covered Features</h2> <ul> <li>Installing the APEX app on a mobile device</li> <li>Making the APEX app available offline</li> <li>Syncing offline requests when getting back online</li> <li>Sending push notifications</li> </ul> <h2 id="documentation">Documentation</h2> <ul> <li><a href="http://vmorneau.me/apex-pwa-part1">Part 1: Introducing Progressive Web Apps</a></li> <li><a href="http://vmorneau.me/apex-pwa-part2">Part 2: Setup and Development Tips</a></li> <li><a href="http://vmorneau.me/apex-pwa-part3">Part 3: JavaScript Recap</a></li> <li><a href="http://vmorneau.me/apex-pwa-part4">Part 4: Installing an APEX App into a Mobile Device</a></li> <li><a href="http://vmorneau.me/apex-pwa-part5">Part 5: Using an APEX App Offline</a></li> <li><a href="http://vmorneau.me/apex-pwa-part6">Part 6: Handling Background Sync</a></li> <li><a href="http://vmorneau.me/apex-pwa-part7">Part 7: Sending Push Notifications</a></li> <li><a href="http://vmorneau.me/apex-pwa-part8">Part 8: Final Thoughts</a></li> </ul> <h2 id="usingmydemoongithub">Using my demo on GitHub</h2> <ol> <li>Import the demo <a href="https://github.com/vincentmorneau/apex-pwa/blob/master/apex/f1694.sql">app</a> on your workspace</li> <li>Meet the requirements listed in <a href="http://vmorneau.me/apex-pwa-part2">Part 2</a></li> <li>Move the following files on your <code>doc_root</code> folder <ul> <li><a href="https://github.com/vincentmorneau/apex-pwa/blob/master/src/manifest.json">src/manifest.json</a></li> <li><a href="https://github.com/vincentmorneau/apex-pwa/blob/master/src/sw.js">src/sw.js</a></li> </ul> </li> <li>Replace the following values in these files <ul> <li><a href="https://github.com/vincentmorneau/apex-pwa/blob/master/src/manifest.json">src/manifest.json</a> <ul> <li>Replace the <code>start_url</code> value with your own application URL</li> </ul> </li> <li><a href="https://github.com/vincentmorneau/apex-pwa/blob/master/server/firebase.json">server/server.js</a> <ul> <li>Replace <code>CHANGE_ME_1</code> with your Firebase service account file</li> <li>Replace <code>CHANGE_ME_2</code> with your email, public key and private key</li> <li>Replace <code>CHANGE_ME_3</code> with your Firebase database URL</li> </ul> </li> </ul> </li> </ol> </div> Vincent Morneau 5b5fd75afc10200623eaca78 Tue Jul 31 2018 07:57:10 GMT-0400 (EDT) Integrando Oracle JET v5.1 en Oracle Apex + Jet TimeLine y PictoChart https://aflorestorres.blogspot.com/2018/07/integrando-oracle-jet-v51-en-oracle.html En este&nbsp;corto&nbsp;tutorial vamos&nbsp;a ver la forma de integrar <b>Oracle Jet v5.1</b> o cualquier version de JET dentro de <b>APEX</b>.<br />Cabe mencionar que puede ser cualquier version de apex, lo he probado en versiones de&nbsp; <b>Apex v5.1</b> y Apex 18.<br /><div class="separator" style="clear: both; text-align: center;"></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-dD556Ep5pEM/W16VeF4gFTI/AAAAAAAAM6U/tZOsonKAlNAy1ViNMaNp3iu2DfyWfELcQCLcBGAs/s1600/caratula2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="378" data-original-width="806" height="186" src="https://3.bp.blogspot.com/-dD556Ep5pEM/W16VeF4gFTI/AAAAAAAAM6U/tZOsonKAlNAy1ViNMaNp3iu2DfyWfELcQCLcBGAs/s400/caratula2.png" width="400" /></a></div><br /><br />Adionalmente en este tutorial he usado referencia a las librerias online de Oracle, en un siguiente tutorial describire como usar nuestro servidor Apache para usar nuestras propias librerias.<br /><br />Video demostrativo:<br /><br /><div class="separator" style="clear: both; text-align: center;"><iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/H8f-OFBJTJQ/0.jpg" src="https://www.youtube.com/embed/H8f-OFBJTJQ?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div><br /><br />Primero agregamos las referencias a las librerias de <b>knockout </b>y <b>require.js</b>:<br /><br /><!-- HTML generated using hilite.me --><br /><div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0;">https:<span style="color: #333333;">//</span><span style="color: #008800; font-weight: bold;">static</span>.oracle.com<span style="color: #333333;">/</span>cdn<span style="color: #333333;">/</span>jet<span style="color: #333333;">/</span>v5.<span style="color: #0000dd; font-weight: bold;">1</span>.<span style="color: #0000dd; font-weight: bold;">0</span><span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">3</span>rdparty<span style="color: #333333;">/</span>knockout<span style="color: #333333;">/</span>knockout<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">3</span>.<span style="color: #0000dd; font-weight: bold;">4</span>.<span style="color: #0000dd; font-weight: bold;">2</span>.js<br />https:<span style="color: #333333;">//</span><span style="color: #008800; font-weight: bold;">static</span>.oracle.com<span style="color: #333333;">/</span>cdn<span style="color: #333333;">/</span>jet<span style="color: #333333;">/</span>v5.<span style="color: #0000dd; font-weight: bold;">1</span>.<span style="color: #0000dd; font-weight: bold;">0</span><span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">3</span>rdparty<span style="color: #333333;">/</span>require<span style="color: #333333;">/</span>require.js<br /></pre></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-garmj_TMlbk/W16PPM7PO3I/AAAAAAAAM5w/R78vBzM_k5QM__YWBvLjvYN7Ko8TO26hQCEwYBhgL/s1600/1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="363" data-original-width="640" src="https://2.bp.blogspot.com/-garmj_TMlbk/W16PPM7PO3I/AAAAAAAAM5w/R78vBzM_k5QM__YWBvLjvYN7Ko8TO26hQCEwYBhgL/s1600/1.png" /></a></div><br />Agregamos la referencia al <b>CSS </b>que utiliza oracle JET, esto lo pegamos en <b>HTML Header</b><br /><br /><!-- HTML generated using hilite.me --><br /><div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #333333;">&lt;</span>link rel<span style="color: #333333;">=</span><span style="color: #aa6600;">"stylesheet"</span> id<span style="color: #333333;">=</span><span style="color: #aa6600;">"css"</span> href<span style="color: #333333;">=</span><span style="color: #aa6600;">"https://static.oracle.com/cdn/jet/v5.1.0/default/css/alta/oj-alta-min.css"</span><span style="color: #333333;">&gt;</span><br /><span style="color: #333333;">&lt;</span>script<span style="color: #333333;">&gt;</span><br /> if (<span style="color: #333333;">!</span>document.createElement) <span style="background-color: #ffaaaa; color: red;">{</span><br /> document.createElement <span style="color: #333333;">=</span> document.<span style="color: #008800; font-weight: bold;">constructor</span>.prototype.createElement;<br /> document.createElementNS <span style="color: #333333;">=</span> document.<span style="color: #008800; font-weight: bold;">constructor</span>.prototype.createElementNS;<br /> document.importNode <span style="color: #333333;">=</span> document.<span style="color: #008800; font-weight: bold;">constructor</span>.prototype.importNode;<br /> <span style="background-color: #ffaaaa; color: red;">}</span><br /><br /> <span style="color: #333333;">//</span> The <span style="color: #aa6600;">"oj_whenReady"</span> <span style="color: #008800; font-weight: bold;">global</span> <span style="color: #008800; font-weight: bold;">variable</span> enables a strategy that the busy context whenReady,<br /> <span style="color: #333333;">//</span> will implicitly <span style="color: #008800; font-weight: bold;">add</span> a busy <span style="color: #008800; font-weight: bold;">state</span>, <span style="color: #008800; font-weight: bold;">until</span> the application calls applicationBoostrapComplete<br /> <span style="color: #333333;">//</span> <span style="color: #008800; font-weight: bold;">on</span> the busy <span style="color: #008800; font-weight: bold;">state</span> context.<br /> window[<span style="color: #aa6600;">"oj_whenReady"</span>] <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">true</span>;<br /><span style="color: #333333;">&lt;/</span>script<span style="color: #333333;">&gt;</span><br /></pre></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-jtLUY0_-oaE/W16PPBeQ-WI/AAAAAAAAM50/D9KLRIbBWzkDjh4ChY8MRGR5n7UDRypdQCEwYBhgL/s1600/2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="377" data-original-width="642" src="https://4.bp.blogspot.com/-jtLUY0_-oaE/W16PPBeQ-WI/AAAAAAAAM50/D9KLRIbBWzkDjh4ChY8MRGR5n7UDRypdQCEwYBhgL/s1600/2.png" /></a></div><br />Luego creamos una acción dinamica, cuando carga la pagina para agregar las librerias de<b> JET 5.1.</b><br />* Podemos aqui utilizar diferentes versiones de jet, en las referencias dejare los links de oracle donde tome el ejemplo.<br /><br /><!-- HTML generated using hilite.me --><br /><div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0;">define(<span style="color: #aa6600;">"knockout"</span>,[],<span style="color: #008800; font-weight: bold;">function</span>()<span style="background-color: #ffaaaa; color: red;">{</span><span style="color: #008800; font-weight: bold;">return</span> ko;<span style="background-color: #ffaaaa; color: red;">}</span>);<br /><br /><br />requirejs.config(<span style="background-color: #ffaaaa; color: red;">{</span><br /> <span style="color: #333333;">//</span> Path mappings <span style="color: #008800; font-weight: bold;">for</span> the logical module <span style="color: #008800; font-weight: bold;">names</span><br /> paths: <span style="background-color: #ffaaaa; color: red;">{</span><br /> <span style="background-color: #fff0f0;">'knockout'</span>: <span style="background-color: #fff0f0;">'https://static.oracle.com/cdn/jet/v5.1.0/3rdparty/knockout/knockout-3.4.2'</span>,<br /> <span style="background-color: #fff0f0;">'jquery'</span>: <span style="background-color: #fff0f0;">'https://static.oracle.com/cdn/jet/v5.1.0/3rdparty/jquery/jquery-3.3.1.min'</span>,<br /> <span style="background-color: #fff0f0;">'jqueryui-amd'</span>: <span style="background-color: #fff0f0;">'https://static.oracle.com/cdn/jet/v5.1.0/3rdparty/jquery/jqueryui-amd-1.12.1.min'</span>,<br /> <span style="background-color: #fff0f0;">'ojs'</span>: <span style="background-color: #fff0f0;">'https://static.oracle.com/cdn/jet/v5.1.0/default/js/min'</span>,<br /> <span style="background-color: #fff0f0;">'ojL10n'</span>: <span style="background-color: #fff0f0;">'https://static.oracle.com/cdn/jet/v5.1.0/default/js/ojL10n'</span>,<br /> <span style="background-color: #fff0f0;">'ojtranslations'</span>: <span style="background-color: #fff0f0;">'https://static.oracle.com/cdn/jet/v5.1.0/default/js/resources'</span>,<br /> <span style="background-color: #fff0f0;">'text'</span>: <span style="background-color: #fff0f0;">'https://static.oracle.com/cdn/jet/v5.1.0/3rdparty/require/text'</span>,<br /> <span style="background-color: #fff0f0;">'promise'</span>: <span style="background-color: #fff0f0;">'https://static.oracle.com/cdn/jet/v5.1.0/3rdparty/es6-promise/es6-promise.min'</span>,<br /> <span style="background-color: #fff0f0;">'hammerjs'</span>: <span style="background-color: #fff0f0;">'https://static.oracle.com/cdn/jet/v5.1.0/3rdparty/hammer/hammer-2.0.8.min'</span>,<br /> <span style="background-color: #fff0f0;">'signals'</span>: <span style="background-color: #fff0f0;">'https://static.oracle.com/cdn/jet/v5.1.0/3rdparty/js-signals/signals.min'</span>,<br /> <span style="background-color: #fff0f0;">'ojdnd'</span>: <span style="background-color: #fff0f0;">'https://static.oracle.com/cdn/jet/v5.1.0/3rdparty/dnd-polyfill/dnd-polyfill-1.0.0.min'</span>,<br /> <span style="background-color: #fff0f0;">'css'</span>: <span style="background-color: #fff0f0;">'https://static.oracle.com/cdn/jet/v5.1.0/3rdparty/require-css/css.min'</span>,<br /> <span style="background-color: #fff0f0;">'customElements'</span>: <span style="background-color: #fff0f0;">'https://static.oracle.com/cdn/jet/v5.1.0/3rdparty/webcomponents/custom-elements.min'</span>,<br /> <span style="background-color: #fff0f0;">'proj4js'</span>: <span style="background-color: #fff0f0;">'https://static.oracle.com/cdn/jet/v5.1.0/3rdparty/proj4js/dist/proj4'</span><br /> <span style="background-color: #ffaaaa; color: red;">}</span>,<br /> <span style="color: #333333;">//</span> Shim configurations <span style="color: #008800; font-weight: bold;">for</span> modules that <span style="color: #008800; font-weight: bold;">do</span> <span style="color: #008800; font-weight: bold;">not</span> expose AMD<br /> shim: <span style="background-color: #ffaaaa; color: red;">{</span><br /> <span style="background-color: #fff0f0;">'jquery'</span>: <span style="background-color: #ffaaaa; color: red;">{</span><br /> exports: [<span style="background-color: #fff0f0;">'jQuery'</span>, <span style="background-color: #fff0f0;">'$'</span>]<br /> <span style="background-color: #ffaaaa; color: red;">}</span><br /> <span style="background-color: #ffaaaa; color: red;">}</span><br /><span style="background-color: #ffaaaa; color: red;">}</span>);<br /></pre></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-sJ9L20QukGY/W16PPEr1wWI/AAAAAAAAM58/o5yv-dq0vz85OzZXzYosepWhu4vbFJENwCEwYBhgL/s1600/3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="305" data-original-width="629" src="https://2.bp.blogspot.com/-sJ9L20QukGY/W16PPEr1wWI/AAAAAAAAM58/o5yv-dq0vz85OzZXzYosepWhu4vbFJENwCEwYBhgL/s1600/3.png" /></a></div><br />Para probar usare el control de TimeLine , el cual saque del <a href="http://www.oracle.com/webfolder/technetwork/jet/jetCookbook.html?component=timeline&amp;demo=contextMenuTimeline" target="_blank">CookBook de oracle Jet</a><br />Creamos un region de tipo static content y en el <b>text </b>copiamos el codigo HTML del cookbook.<br /><br /><!-- HTML generated using hilite.me --><br /><div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #333333;">&lt;</span>div id<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'timeline-container'</span><span style="color: #333333;">&gt;</span><br /> <span style="color: #333333;">&lt;</span>oj<span style="color: #333333;">-</span>timeline id<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'timeline'</span> aria<span style="color: #333333;">-</span>label<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'Timeline Context Menu Demo'</span> <br /> minor<span style="color: #333333;">-</span>axis<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'{</span><br /><span style="background-color: #fff0f0;"> "scale": "weeks",</span><br /><span style="background-color: #fff0f0;"> "zoomOrder": ["months", "weeks", "days"]</span><br /><span style="background-color: #fff0f0;"> }'</span><br /> major<span style="color: #333333;">-</span>axis.<span style="color: #008800; font-weight: bold;">scale</span><span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'quarters'</span><br /> <span style="color: #008800; font-weight: bold;">start</span><span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'[[new Date("Jan 1, 2013").toISOString()]]'</span><br /> <span style="color: #008800; font-weight: bold;">end</span><span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'[[new Date("Dec 31, 2013").toISOString()]]'</span><br /> selection<span style="color: #333333;">-</span><span style="color: #008800; font-weight: bold;">mode</span><span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'single'</span><br /> selection<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'["e4"]'</span><br /> series<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'[[timelineSeries]]'</span><br /> style<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'width:100%;height:350px'</span><span style="color: #333333;">&gt;</span><br /> <span style="color: #333333;">&lt;</span>oj<span style="color: #333333;">-</span>menu slot<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'contextMenu'</span> style<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'display:none'</span> aria<span style="color: #333333;">-</span>label<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'Match Edit'</span> <br /> <span style="color: #008800; font-weight: bold;">on</span><span style="color: #333333;">-</span>oj<span style="color: #333333;">-</span>action<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'[[menuItemAction]]'</span> <br /> <span style="color: #008800; font-weight: bold;">on</span><span style="color: #333333;">-</span>oj<span style="color: #333333;">-</span><span style="color: #008800; font-weight: bold;">before</span><span style="color: #333333;">-</span><span style="color: #008800; font-weight: bold;">open</span><span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'[[beforeOpenFunction]]'</span><span style="color: #333333;">&gt;</span><br /> <span style="color: #333333;">&lt;</span>oj<span style="color: #333333;">-</span><span style="color: #008800; font-weight: bold;">option</span> value<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'action1'</span><span style="color: #333333;">&gt;</span>Action <span style="color: #0000dd; font-weight: bold;">1</span><span style="color: #333333;">&lt;/</span>oj<span style="color: #333333;">-</span><span style="color: #008800; font-weight: bold;">option</span><span style="color: #333333;">&gt;</span><br /> <span style="color: #333333;">&lt;</span>oj<span style="color: #333333;">-</span><span style="color: #008800; font-weight: bold;">option</span> value<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'action2'</span><span style="color: #333333;">&gt;</span>Action <span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">&lt;/</span>oj<span style="color: #333333;">-</span><span style="color: #008800; font-weight: bold;">option</span><span style="color: #333333;">&gt;</span><br /> <span style="color: #333333;">&lt;</span>oj<span style="color: #333333;">-</span><span style="color: #008800; font-weight: bold;">option</span> value<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'action3'</span><span style="color: #333333;">&gt;</span>Action <span style="color: #0000dd; font-weight: bold;">3</span><span style="color: #333333;">&lt;/</span>oj<span style="color: #333333;">-</span><span style="color: #008800; font-weight: bold;">option</span><span style="color: #333333;">&gt;</span><br /> <span style="color: #333333;">&lt;/</span>oj<span style="color: #333333;">-</span>menu<span style="color: #333333;">&gt;</span><br /> <span style="color: #333333;">&lt;/</span>oj<span style="color: #333333;">-</span>timeline<span style="color: #333333;">&gt;</span><br /> <br /> <span style="color: #333333;">&lt;</span>p<span style="color: #333333;">&gt;</span><span style="color: #008800; font-weight: bold;">Last</span> selected menu item:<br /> <span style="color: #333333;">&lt;</span>span id<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'results'</span> <span style="color: #008800; font-weight: bold;">class</span><span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'italic'</span> style<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'font-weight:bold'</span> <span style="color: #008800; font-weight: bold;">data</span><span style="color: #333333;">-</span>bind<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'text: selectedMenuItem'</span><span style="color: #333333;">&gt;&lt;/</span>span<span style="color: #333333;">&gt;</span><br /> <span style="color: #333333;">&lt;/</span>p<span style="color: #333333;">&gt;</span><br /> <span style="color: #333333;">&lt;/</span>div<span style="color: #333333;">&gt;</span><br /></pre></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-YWUPkcmQrHk/W16PP9OQJHI/AAAAAAAAM54/KAfVQVpY1XEoXQbMKYfb3X7SF0ihX3YCQCEwYBhgL/s1600/4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="309" data-original-width="606" src="https://3.bp.blogspot.com/-YWUPkcmQrHk/W16PP9OQJHI/AAAAAAAAM54/KAfVQVpY1XEoXQbMKYfb3X7SF0ihX3YCQCEwYBhgL/s1600/4.png" /></a></div><br /><br />Y luego creamos un boton que llame una accion dinamica para crear el ViewModel (JS) del control.<br /><br /><!-- HTML generated using hilite.me --><br /><div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0;">require([<span style="background-color: #fff0f0;">'ojs/ojcore'</span>, <span style="background-color: #fff0f0;">'knockout'</span>, <span style="background-color: #fff0f0;">'jquery'</span>, <span style="background-color: #fff0f0;">'ojs/ojknockout'</span>, <span style="background-color: #fff0f0;">'ojs/ojmenu'</span>, <span style="background-color: #fff0f0;">'ojs/ojtimeline'</span>],<br /> <span style="color: #008800; font-weight: bold;">function</span> (oj, ko, <span style="background-color: #ffaaaa; color: red;">$</span>)<br /> <span style="background-color: #ffaaaa; color: red;">{</span><br /> <span style="color: #008800; font-weight: bold;">function</span> ViewModel()<br /> <span style="background-color: #ffaaaa; color: red;">{</span><br /> var <span style="color: #008800; font-weight: bold;">self</span> <span style="color: #333333;">=</span> this;<br /> <br /> <span style="color: #008800; font-weight: bold;">self</span>.seriesData <span style="color: #333333;">=</span> [<span style="background-color: #ffaaaa; color: red;">{</span><br /> id: <span style="background-color: #fff0f0;">'e1'</span>,<br /> title: <span style="background-color: #fff0f0;">'ATP VTR Open'</span>,<br /> <span style="color: #008800; font-weight: bold;">start</span>: <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #007020;">Date</span>(<span style="background-color: #fff0f0;">'Feb 4, 2013'</span>).toISOString(),<br /> <span style="color: #008800; font-weight: bold;">end</span>: <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #007020;">Date</span>(<span style="background-color: #fff0f0;">'Feb 10, 2013'</span>).toISOString(),<br /> description: <span style="background-color: #fff0f0;">'Finalist: 3-1'</span><br /> <span style="background-color: #ffaaaa; color: red;">}</span>, <span style="background-color: #ffaaaa; color: red;">{</span><br /> id: <span style="background-color: #fff0f0;">'e2'</span>,<br /> title: <span style="background-color: #fff0f0;">'ATP Brasil Open'</span>,<br /> <span style="color: #008800; font-weight: bold;">start</span>: <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #007020;">Date</span>(<span style="background-color: #fff0f0;">'Feb 11, 2013'</span>).toISOString(),<br /> <span style="color: #008800; font-weight: bold;">end</span>: <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #007020;">Date</span>(<span style="background-color: #fff0f0;">'Feb 17, 2013'</span>).toISOString(),<br /> description: <span style="background-color: #fff0f0;">'Champion: 4-0'</span><br /> <span style="background-color: #ffaaaa; color: red;">}</span>, <span style="background-color: #ffaaaa; color: red;">{</span><br /> id: <span style="background-color: #fff0f0;">'e3'</span>,<br /> title: <span style="background-color: #fff0f0;">'ATP Abierto Mexicano Telcel'</span>,<br /> <span style="color: #008800; font-weight: bold;">start</span>: <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #007020;">Date</span>(<span style="background-color: #fff0f0;">'Feb 25, 2013'</span>).toISOString(),<br /> <span style="color: #008800; font-weight: bold;">end</span>: <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #007020;">Date</span>(<span style="background-color: #fff0f0;">'Mar 2, 2013'</span>).toISOString(),<br /> description: <span style="background-color: #fff0f0;">'Champion: 5-0'</span><br /> <span style="background-color: #ffaaaa; color: red;">}</span>, <span style="background-color: #ffaaaa; color: red;">{</span><br /> id: <span style="background-color: #fff0f0;">'e4'</span>,<br /> title: <span style="background-color: #fff0f0;">'ATP BNP Paribas Open'</span>,<br /> <span style="color: #008800; font-weight: bold;">start</span>: <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #007020;">Date</span>(<span style="background-color: #fff0f0;">'Mar 7, 2013'</span>).toISOString(),<br /> <span style="color: #008800; font-weight: bold;">end</span>: <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #007020;">Date</span>(<span style="background-color: #fff0f0;">'Mar 17, 2013'</span>).toISOString(),<br /> description: <span style="background-color: #fff0f0;">'Champion: 6-0'</span><br /> <span style="background-color: #ffaaaa; color: red;">}</span><br /> ];<br /> var items <span style="color: #333333;">=</span> ko.observableArray(<span style="color: #008800; font-weight: bold;">self</span>.seriesData)();<br /> <span style="color: #008800; font-weight: bold;">self</span>.timelineSeries <span style="color: #333333;">=</span> [<span style="background-color: #ffaaaa; color: red;">{</span>id: <span style="background-color: #fff0f0;">'s1'</span>, emptyText: <span style="background-color: #fff0f0;">'No Data.'</span>, label:<span style="background-color: #fff0f0;">'Oracle Events'</span>, items: items<span style="background-color: #ffaaaa; color: red;">}</span>];<br /><br /> <span style="color: #008800; font-weight: bold;">self</span>.selectedMenuItem <span style="color: #333333;">=</span> ko.observable(<span style="background-color: #fff0f0;">'(None selected yet)'</span>);<br /> var itemTitle;<br /> <span style="color: #008800; font-weight: bold;">self</span>.beforeOpenFunction <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">function</span> (event)<br /> <span style="background-color: #ffaaaa; color: red;">{</span><br /> var target <span style="color: #333333;">=</span> event.detail.originalEvent.target;<br /> var context <span style="color: #333333;">=</span> document.getElementById(<span style="background-color: #fff0f0;">'timeline'</span>).getContextByNode(target);<br /> if (context <span style="color: #333333;">!=</span> <span style="color: #008800; font-weight: bold;">null</span> <span style="color: #333333;">&amp;&amp;</span> context.subId <span style="color: #333333;">==</span> <span style="background-color: #fff0f0;">'oj-timeline-item'</span>)<br /> <span style="background-color: #ffaaaa; color: red;">{</span><br /> var itemIndex <span style="color: #333333;">=</span> context[<span style="background-color: #fff0f0;">'itemIndex'</span>];<br /> itemTitle <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">self</span>.seriesData[itemIndex][<span style="background-color: #fff0f0;">'title'</span>];<br /> <span style="background-color: #ffaaaa; color: red;">}</span><br /> <span style="background-color: #ffaaaa; color: red;">}</span>;<br /> <span style="color: #008800; font-weight: bold;">self</span>.menuItemAction <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">function</span> (event)<br /> <span style="background-color: #ffaaaa; color: red;">{</span><br /> var <span style="color: #007020;">text</span> <span style="color: #333333;">=</span> event.target.textContent;<br /> if (itemTitle)<br /> <span style="background-color: #ffaaaa; color: red;">{</span><br /> <span style="color: #008800; font-weight: bold;">self</span>.selectedMenuItem(<span style="color: #007020;">text</span> <span style="color: #333333;">+</span> <span style="background-color: #fff0f0;">' from '</span> <span style="color: #333333;">+</span> itemTitle);<br /> itemTitle <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">null</span>;<br /> <span style="background-color: #ffaaaa; color: red;">}</span><br /> <span style="color: #008800; font-weight: bold;">else</span><br /> <span style="color: #008800; font-weight: bold;">self</span>.selectedMenuItem(<span style="color: #007020;">text</span> <span style="color: #333333;">+</span> <span style="background-color: #fff0f0;">' from timeline background'</span>);<br /> <span style="background-color: #ffaaaa; color: red;">}</span>;<br /> <span style="background-color: #ffaaaa; color: red;">}</span>;<br /><br /> <span style="background-color: #ffaaaa; color: red;">$</span>(<br /> <span style="color: #008800; font-weight: bold;">function</span>()<br /> <span style="background-color: #ffaaaa; color: red;">{</span><br /> ko.applyBindings(<span style="color: #008800; font-weight: bold;">new</span> ViewModel(), document.getElementById(<span style="background-color: #fff0f0;">'timeline-container'</span>));<br /> <span style="background-color: #ffaaaa; color: red;">}</span><br /> );<br /> <span style="background-color: #ffaaaa; color: red;">}</span><br />);<br /></pre></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-BWscHqLSq1Y/W16PQZuzQLI/AAAAAAAAM58/3x6InxrbIRM7zBNhT1whdPe93DWfrLXKwCEwYBhgL/s1600/5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="359" data-original-width="638" src="https://2.bp.blogspot.com/-BWscHqLSq1Y/W16PQZuzQLI/AAAAAAAAM58/3x6InxrbIRM7zBNhT1whdPe93DWfrLXKwCEwYBhgL/s1600/5.png" /></a></div><br />Finalmente tenemos nuestro TimeLine en Apex Oracle<br /><br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-Fi3E3RbeJu4/W16TPLtu91I/AAAAAAAAM6I/BUB1DfVe1HAMCvlrU1MPYP2QEkECM6EegCLcBGAs/s1600/6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="677" src="https://2.bp.blogspot.com/-Fi3E3RbeJu4/W16TPLtu91I/AAAAAAAAM6I/BUB1DfVe1HAMCvlrU1MPYP2QEkECM6EegCLcBGAs/s1600/6.png" /></a></div><br />Aplicación demo:<br /><br /><br /><ul><li><a href="https://drive.google.com/drive/folders/1w0bbNfHwW0tTxLoQfyKQE9E9uAT2_W7e" target="_blank">Link</a></li></ul><br /><br />Referencias:<br /><br /><br /><ul><li><a href="http://www.oracle.com/webfolder/technetwork/jet/jetCookbook.html" target="_blank">CookBook Oracle Jet</a></li><li><a href="https://docs.oracle.com/middleware/jet400/jet/developer/GUID-219A636B-0D0B-4A78-975B-0528497A82DD.htm#JETDG-GUID-219A636B-0D0B-4A78-975B-0528497A82DD" target="_blank">Link oracle jet 4.0.0 online</a></li><li><a href="https://docs.oracle.com/en/middleware/jet/5/develop/loading-oracle-jet-cdn.html#GUID-219A636B-0D0B-4A78-975B-0528497A82DD" target="_blank">Link oracle jet 5.0.0 online</a></li><li><a href="http://www.oracle.com/webfolder/technetwork/jet/jetCookbook.html?component=timeline&amp;demo=contextMenuTimeline" target="_blank">CookBook TimeLine</a></li><li><a href="http://www.oracle.com/webfolder/technetwork/jet/jetCookbook.html?component=pictoChart&amp;demo=layout" target="_blank">CookBook PictoChar</a></li><li><a href="https://jsfiddle.net/lucasjellema/5abpdgt9/" target="_blank">Extra 1</a></li><li><a href="https://docs.oracle.com/en/middleware/jet/5.1/develop/understanding-path-mapping-script-file-and-configuration-options.html" target="_blank">Extra 2</a></li><li><a href="https://stackoverflow.com/questions/49740260/how-to-integrate-gantt-oracle-jet-chart-in-oracle-apex-5-1" target="_blank">Extra 3</a></li></ul><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /> Angel O. Flores Torres tag:blogger.com,1999:blog-2893325831811936253.post-8235579373202371109 Mon Jul 30 2018 01:04:00 GMT-0400 (EDT) Exporting APEX Application in SQLcl with Build Status Override http://www.talkapex.com/2018/07/exporting-apex-application-in-sqlcl-with-build-status-override/ <p><a href="https://www.oracle.com/technetwork/developer-tools/sqlcl/overview/index.html" target="_blank" rel="noopener">SQLcl</a> has a great feature to easily export an APEX application.</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">&gt; sqlcl giffy/giffy@localhost:32122/orclpdb1810.localdomain</span><br><span class="line"></span><br><span class="line">SQLcl: Release 18.2 Production on Sat Jul 28 08:12:13 2018</span><br><span class="line"></span><br><span class="line">Copyright (c) 1982, 2018, Oracle. All rights reserved.</span><br><span class="line"></span><br><span class="line">Last Successful login time: Sat Jul 28 2018 08:12:20 -04:00</span><br><span class="line"></span><br><span class="line">Connected to:</span><br><span class="line">Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production</span><br><span class="line"></span><br><span class="line">SQL&gt; apex <span class="built_in">export</span> 100</span><br><span class="line">Exporting application 100 Completed at Sat Jul 28 08:13:14 EDT 2018</span><br><span class="line"></span><br><span class="line">SQL&gt;</span><br></pre></td></tr></table></figure><p>This will produce a file in the current directory called <code>f100.sql</code>.</p><p>I was recently asked how to export an application using SQLcl and set the <code>Build Status Override</code> option. This is available when manually exporting the application as shown below. This option is usually set to <code>Run Application Only</code> in production environments to prevent others from modifying the application.</p><img src="/2018/07/exporting-apex-application-in-sqlcl-with-build-status-override/Snip20180728_32.png"><p>There is no option <em>(that I know of)</em> to set the <code>Build Status Override</code> option when doing an SQLcl export. After doing a diff between manual exports with the different settings for <code>Build Status Override</code> the only change is the parameter <code>p_build_status=&gt; &#39;RUN_ONLY&#39;</code>:</p><img src="/2018/07/exporting-apex-application-in-sqlcl-with-build-status-override/Snip20180728_28.png"><p>If you want to create an application export for a run only environment (i.e. production) just run the following bash commands after the export:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">APEX_APP_ID=100</span><br><span class="line">sed -i.bu <span class="string">"s/wwv_flow_api.create_flow(/wwv_flow_api.create_flow(p_build_status=&gt; 'RUN_ONLY',/g"</span> f<span class="variable">$APEX_APP_ID</span>.sql</span><br><span class="line"></span><br><span class="line">mv f<span class="string">"<span class="variable">$APEX_APP_ID</span>"</span>.sql.bu f<span class="string">"<span class="variable">$APEX_APP_ID</span>"</span>_run_and_build.sql</span><br><span class="line">mv f<span class="string">"<span class="variable">$APEX_APP_ID</span>"</span>.sql f<span class="string">"<span class="variable">$APEX_APP_ID</span>"</span>_run_only.sql</span><br></pre></td></tr></table></figure><p>This will produce two files:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&gt; ls -1 f*.sql</span><br><span class="line"></span><br><span class="line">f100_run_and_build.sql</span><br><span class="line">f100_run_only.sql</span><br></pre></td></tr></table></figure> Martin Giffy D'Souza http://www.talkapex.com/2018/07/exporting-apex-application-in-sqlcl-with-build-status-override/ Sat Jul 28 2018 10:09:02 GMT-0400 (EDT) Apex Quick Tip for Devs: Url including Workspace https://svenweller.wordpress.com/2018/07/27/apex-quick-tip-for-devs-url-including-workspace/ <h1>scenario</h1> <p>If you are like me and are using many workspaces, it is easy to get lost which workspace works on which host and I also tend to mix up/forget workspace names. The easy solution is to have bookmarks/favorites that store access to a specific the workspace.</p> <p>However this doesn&#8217;t work out of the box. </p> <p>If the login page on the same host is called a second time, then the workspace name stays. This is implemented via a cookie (ORA_WWV_REMEMBER_UN in Apex 18+). The cookie stores the most recent workspace name and user name for a certain time. If you have several different workspaces under the same url, the cookie will only remember the last one. If you try to bookmark this url, then it will always show the most recent workspace not active one when you bookmarked it. And not even the last workspace might be remembered once you come back from vacation, because the cookie expired meanwhile.</p> <p>APEX is written in APEX. We can use our knowledge about APEX urls, to set the correct workspace via url parameters.</p> <h1>solution</h1> <p>The login page for the internal apex application 4550 is page 1.<br /> We can inspect the login page to find out about the correct item name.<br /> <img data-attachment-id="7867" data-permalink="https://svenweller.wordpress.com/2018/07/27/apex-quick-tip-for-devs-url-including-workspace/inspect_workspace_item/" data-orig-file="https://svenweller.files.wordpress.com/2018/07/inspect_workspace_item.png?w=809" data-orig-size="981,705" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="inspect_workspace_item" data-image-description="" data-medium-file="https://svenweller.files.wordpress.com/2018/07/inspect_workspace_item.png?w=809?w=300" data-large-file="https://svenweller.files.wordpress.com/2018/07/inspect_workspace_item.png?w=809?w=809" src="https://svenweller.files.wordpress.com/2018/07/inspect_workspace_item.png?w=809" alt="inspect_workspace_item" class="alignnone size-full wp-image-7867" srcset="https://svenweller.files.wordpress.com/2018/07/inspect_workspace_item.png?w=809 809w, https://svenweller.files.wordpress.com/2018/07/inspect_workspace_item.png?w=150 150w, https://svenweller.files.wordpress.com/2018/07/inspect_workspace_item.png?w=300 300w, https://svenweller.files.wordpress.com/2018/07/inspect_workspace_item.png?w=768 768w, https://svenweller.files.wordpress.com/2018/07/inspect_workspace_item.png 981w" sizes="(max-width: 809px) 100vw, 809px" /></p> <p>The field with the workspace name is <strong>F4550_P1_COMPANY</strong>.<br /> Simply supply the name of item and the value (=workspace name) like in any other apex application to the url. </p> <p>Here is an example for apex.oracle.com. One of my workspace names is &#8220;SYNTESTWS&#8221;. And this will be the url, that I bookmark.</p> <pre>https://apex.oracle.com/pls/apex/f?p=4550:1:::::<strong>F4550_P1_COMPANY</strong>:<span style="color:blue;">SYNTESTWS</span></pre> <p>It also works with the username. Although I find that slightly less useful.</p> <pre>https://apex.oracle.com/pls/apex/f?p=4550:1:::::F4550_P1_COMPANY,F4550_P1_USERNAME:SYNTEGRIS,MYSELF</pre> <p>If you copy a real url, don&#8217;t forget to remove the session identifier information from the url. It does not make sense to bookmark that.</p> <h1>other related information</h1> <p>In Apex 18 the cookie info was improves (more in compliance with GDPR I think).<br /> <img data-attachment-id="7865" data-permalink="https://svenweller.wordpress.com/2018/07/27/apex-quick-tip-for-devs-url-including-workspace/apex_workspace_url/" data-orig-file="https://svenweller.files.wordpress.com/2018/07/apex_workspace_url.png?w=809" data-orig-size="1225,823" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="apex_workspace_url" data-image-description="" data-medium-file="https://svenweller.files.wordpress.com/2018/07/apex_workspace_url.png?w=809?w=300" data-large-file="https://svenweller.files.wordpress.com/2018/07/apex_workspace_url.png?w=809?w=809" src="https://svenweller.files.wordpress.com/2018/07/apex_workspace_url.png?w=809" alt="apex_workspace_url" class="alignnone size-full wp-image-7865" srcset="https://svenweller.files.wordpress.com/2018/07/apex_workspace_url.png?w=809 809w, https://svenweller.files.wordpress.com/2018/07/apex_workspace_url.png?w=150 150w, https://svenweller.files.wordpress.com/2018/07/apex_workspace_url.png?w=300 300w, https://svenweller.files.wordpress.com/2018/07/apex_workspace_url.png?w=768 768w, https://svenweller.files.wordpress.com/2018/07/apex_workspace_url.png?w=1024 1024w, https://svenweller.files.wordpress.com/2018/07/apex_workspace_url.png 1225w" sizes="(max-width: 809px) 100vw, 809px" /></p> <p>The parts of the url (especially the &#8220;p&#8221; parameter of the &#8220;f&#8221; function) are documented:<br /> <a href="https://docs.oracle.com/database/apex-18.1/HTMDB/understanding-url-syntax.htm#GUID-D5510BFC-AF94-4AAD-8B82-FF780A47601D" target="_blank">Apex url syntax</a><br /> <img data-attachment-id="7868" data-permalink="https://svenweller.wordpress.com/2018/07/27/apex-quick-tip-for-devs-url-including-workspace/url_set_items/" data-orig-file="https://svenweller.files.wordpress.com/2018/07/url_set_items.png?w=809" data-orig-size="780,261" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="url_set_items" data-image-description="" data-medium-file="https://svenweller.files.wordpress.com/2018/07/url_set_items.png?w=809?w=300" data-large-file="https://svenweller.files.wordpress.com/2018/07/url_set_items.png?w=809?w=780" src="https://svenweller.files.wordpress.com/2018/07/url_set_items.png?w=809" alt="url_set_items" class="alignnone size-full wp-image-7868" srcset="https://svenweller.files.wordpress.com/2018/07/url_set_items.png 780w, https://svenweller.files.wordpress.com/2018/07/url_set_items.png?w=150 150w, https://svenweller.files.wordpress.com/2018/07/url_set_items.png?w=300 300w, https://svenweller.files.wordpress.com/2018/07/url_set_items.png?w=768 768w" sizes="(max-width: 780px) 100vw, 780px" /><br /> Also my <a href="https://svenweller.files.wordpress.com/2018/07/qr_apexapi_en_v2-0.pdf" title="QR_ApexApi_EN_v2.0">Apex Quick Reference</a> which sports Apex url syntax as a quick lookup tool and the next Syntegris 2019 calendar will feature Apex Urls. So try to get one of those during the next conferences (cu at DOAG 2018).</p> svenweller http://svenweller.wordpress.com/?p=7863 Fri Jul 27 2018 05:18:30 GMT-0400 (EDT) Simplified E-Business Suite Development -Think Oracle APEX https://insum.ca/simplified-cost-effective-development-in-ebs-think-oracle-apex/ <p>When it comes to extending applications in the Oracle E-Business Suite Environment, EBS Developers and their managers have been presented with some difficult options over the years. To understand where they are coming from, you must go back to the beginnings of EBS Development.</p> <h2><strong>Forms Development in E-Business Suite</strong></h2> <p>EBS was originally put together with SQL*Forms, which was a far cry from any Application Development Framework we know today. Then came Oracle Forms 4.0, which was the first Oracle &#8220;Internet Computing&#8221; tool, around 1994.  From that point on, EBS converted and expanded with this GUI tool. Every EBS customer still has Forms-based applications in their systems. As a matter of fact, some of the most popular EBS modules, such as G/L, Accounts Payable, and Accounts Receivable continue to be Forms-based.  It’s probably one of the reasons Oracle, thankfully, is keeping Forms up to date. But, Forms is no longer the development platform of choice for the newer generations of EBS.</p> <h2><strong>Towards Web-based development in E-Business Suite</strong></h2> <p>The change from Forms-based development began when Oracle introduced a way to develop web pages in EBS.  This came up in early  2000 with EBS version 11i (11.5.1). With the introduction of Oracle Application Framework (OAF). One of the first modules to have web pages was Self-Service Human Resources. Then, many others appeared, like iProcurement, iStore, etc. Thus, Oracle began veering development away from the PL/SQL Forms-based platform to the Java-based Platform that is OAF. Suddenly, many Forms programmers felt they had to learn Java and deal with Object-oriented instead of declarative development and PL/SQL.</p> <h2><strong>Development using OAF</strong></h2> <p>For example, when EBS R12 was first released in 2007, extending or modifying web pages would go through OAF, the application framework that runs E-BusinessSuite’s web-based content. It was extremely confusing. Having experienced it firsthand, I would even call it a horrible adventure.</p> <p>First (this is still true), you need the right version of JDeveloper to match OAF in your EBS instance.  OAF has its own special relationship with JDev!  You may even have to downgrade your existing version since OAF was developed and remains with old Java versions. Then, developing in an object-oriented paradigm is quite different than the structured SQL and PL/SQL concept that Oracle database developers are used to.</p> <p>I think these complexities are why I’ve not met many EBS developers using OAF on a regular basis.</p> <h2><strong>Development with ADF</strong></h2> <p>When the ADF framework became a recommended solution for EBS development, it was described as “<a href="https://www.oracle.com/technetwork/developer-tools/adf/adf11g-data-sheet-1-133847.pdf">an end-to-end development framework…offering unparalleled productivity to application developers</a>”. More powerful than OAF, it enables you to build applications from scratch.  Oracle actually used ADF to build Fusion Applications.  But, I’ve often heard it has a very steep learning curve. As I’ve never worked with ADF, I can’t pass judgement on it, but no companies I’ve worked with have adopted it.</p> <p>Interestingly, Oracle <a href="https://blogs.oracle.com/shay/to-adf-or-to-oaf-or-can-i-use-adf-with-oracle-e-business-suite">recommended</a> ADF for things like “building a Mobile UI for EBS”, creating “a rich dashboard with lots of interactive graphs” or to build a system that “brings together data from both EBS as well as other sources of data”.  These are all things that another application development platform can handle with ease.</p> <h2><strong>Using Oracle Application Express (APEX)</strong></h2> <p>If you’re not familiar with Oracle APEX at all, I recommend you start by reading <a href="https://insum.ca/learn-apex/about-oracle-apex/">this web page</a>. Or this <a href="https://insum.ca/top-5-questions-people-ask-about-apex/">blog post</a>.</p> <p>Oracle APEX is a Low-Code, Rapid Application Development framework that’s easy to learn and easy to work with. Since it is a no-cost feature of the Oracle Database, it can be used with no additional licencing fees.</p> <p>Contrary to the Java-based OAF and ADF, it is PL/SQL-based. This means EBS and Forms developers will feel right at home with its approach. Yet, APEX is an open architecture which allows web-based technologies like JavaScript,  jQuery, CSS3, HTML5, etc. to be incorporated without limits.</p> <p>It’s an Ideal tool to create Forms or EBS extensions like interactive reports, Forms, dashboards, etc.  I’ll get more into detail on that in a later blog.</p> <p>In APEX you can create responsive mobile applications as well. You can very easily consolidate your data from Excel spreadsheets or other sources to enable data validation, removal of multiple versions and increased safety.</p> <p>APEX&#8217;s Interactive Reports allows users to customize reports on the fly, using real-time access to most any data they&#8217;d like.</p> <p>What&#8217;s more, APEX is a declarative drag-and-drop development environment. It enables you to work very quickly and get down to the essentials of the business problem. Since you aren&#8217;t bogged down by the development and design processes, you can put together a proof of concept incredibly quickly.</p> <h2><strong>The Proof of Concept</strong></h2> <p>I’ve found the best way to get a prospective customer to understand the value of an APEX solution for E-Business Suite is to quickly provide a proof of concept. The same can apply to an EBS developer working with APEX and looking for project approval within his company.</p> <p>I’ve presented proof of concepts to business Analysts and Functional Analysts. For example, when I’ve shown interactive reports,  a reaction I often get is “That must have taken you a lot of time”. My answer is invariably “No.” I then explain that what takes up the most time is putting the SQL script together. That takes care of all the report parameters. Then, they just need to be fed.</p> <p><img class="wp-image-12035 size-large aligncenter" src="https://insum.ca/wp-content/uploads/2018/07/EBS-Blog-E-Business-Suite-IR-SQL-600x450.jpg" alt="E-Business Suite Interactive Report Result" width="600" height="450" srcset="https://insum.ca/wp-content/uploads/2018/07/EBS-Blog-E-Business-Suite-IR-SQL-600x450.jpg 600w, https://insum.ca/wp-content/uploads/2018/07/EBS-Blog-E-Business-Suite-IR-SQL-300x225.jpg 300w, https://insum.ca/wp-content/uploads/2018/07/EBS-Blog-E-Business-Suite-IR-SQL-450x338.jpg 450w, https://insum.ca/wp-content/uploads/2018/07/EBS-Blog-E-Business-Suite-IR-SQL.jpg 720w" sizes="(max-width: 600px) 100vw, 600px" /></p> <p>Because SQL language is a native to the database and directly accesses it, clients can proceed to filter columns, create new ones etc., on the spot. There’s no other development needed as everything is there by default.</p> <p><img class="aligncenter wp-image-12036 size-full" src="https://insum.ca/wp-content/uploads/2018/07/EBS-Blog-E-Business-Suite-IR-Result.jpg" alt="E-Business suite Interactive Report Result" width="1440" height="745" srcset="https://insum.ca/wp-content/uploads/2018/07/EBS-Blog-E-Business-Suite-IR-Result.jpg 1440w, https://insum.ca/wp-content/uploads/2018/07/EBS-Blog-E-Business-Suite-IR-Result-300x155.jpg 300w, https://insum.ca/wp-content/uploads/2018/07/EBS-Blog-E-Business-Suite-IR-Result-768x397.jpg 768w, https://insum.ca/wp-content/uploads/2018/07/EBS-Blog-E-Business-Suite-IR-Result-600x310.jpg 600w, https://insum.ca/wp-content/uploads/2018/07/EBS-Blog-E-Business-Suite-IR-Result-880x455.jpg 880w, https://insum.ca/wp-content/uploads/2018/07/EBS-Blog-E-Business-Suite-IR-Result-450x233.jpg 450w" sizes="(max-width: 1440px) 100vw, 1440px" /></p> <p>If there are adjustments, they are usually minor. In fact, they are more to optimize performance or to make the interface more user-friendly. But this requires little effort.</p> <p>I find proofs of concept take away a lot of the need to explain, nuance, correcting perceptions and misunderstandings. It gives the solution credibility and fires up their imaginations on how they’ll be able to use it.</p> <h2>We can Help</h2> <p>Want to read more on APEX for EBS? How about learning the <a href="https://insum.ca/top-reasons-use-oracle-apex-to-build-ebs-extensions/">Top 5 reasons to use Oracle APEX to Build EBS Extensions</a>?</p> <p>Would you like to see APEX first hand? Do you have an E-Business Suite proof of concept you need to develop for a project? We’d be happy to help!</p> <p><a href="https://insum.ca/contact/">Contact Us!</a></p> <p>&nbsp;</p> <p>&nbsp;</p> <p>&nbsp;</p> <p>&nbsp;</p> <p>&nbsp;</p> <p>&nbsp;</p> <p><em>Photo by <a href="https://unsplash.com/photos/FUgsdoB6VH4?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Robert Trombetta</a> on <a href="https://unsplash.com/search/photos/software-development?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></em></p> <p>The post <a rel="nofollow" href="https://insum.ca/simplified-cost-effective-development-in-ebs-think-oracle-apex/">Simplified E-Business Suite Development -Think Oracle APEX</a> appeared first on <a rel="nofollow" href="https://insum.ca">Insum</a>.</p> Jocelyn Coté https://insum.ca/?p=12003 Wed Jul 25 2018 09:01:38 GMT-0400 (EDT) Cómo desmarcar el Row Selector del primer registro en el Interactive Grid en APEX 18.1 http://feedproxy.google.com/~r/DescubriendoElMundoDeOracle/~3/7JtaxgTpBFs/como-desmarcar-el-row-selector-del.html Hola, hoy quiero compartir algo que quizás no esta tan a la mano por ser la versión más reciente, hablando de APEX 18.1 ya que para la versión de APEX 5.1 se trabaja de otra forma.<br /><br />Veamos el siguiente ejemplo: creamos una página con una grilla interactiva editable de la tabla EMP.&nbsp; <br /><br />Como podemos ver por defecto siempre la grilla interactiva esta seleccionada la primera fila y marcado el check del <b>Row Selector</b>:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-uo9Yz0CcLTo/W1e5HuuQqWI/AAAAAAAAMEk/SSauAssEDGQZYr-FjCxrMULBNZvg_xxBQCLcBGAs/s1600/img1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="435" data-original-width="1600" height="107" src="https://2.bp.blogspot.com/-uo9Yz0CcLTo/W1e5HuuQqWI/AAAAAAAAMEk/SSauAssEDGQZYr-FjCxrMULBNZvg_xxBQCLcBGAs/s400/img1.png" width="400" /></a></div><br />La idea es que cuando se cargue la grilla no se seleccione ninguna fila por defecto.<br /><br />Para ello, primero a la región del IG le colocamos un Identificador Estático, por ejemplo <b>emp</b>.<br /><br />Segundo en Propiedades de la Pagina, en "Execute when Page Loads" ingresamos el siguiente código:<br /><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">apex.region("emp").widget().interactiveGrid("setSelectedRecords", []);</span><br /><div><br /><a name='more'></a><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-4KAGIAagz-I/W1e6Go5GvdI/AAAAAAAAMEs/mep7nE4a8oYYRXNZFBhSspxcKfZeGd7GACLcBGAs/s1600/img2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="625" data-original-width="1600" height="156" src="https://2.bp.blogspot.com/-4KAGIAagz-I/W1e6Go5GvdI/AAAAAAAAMEs/mep7nE4a8oYYRXNZFBhSspxcKfZeGd7GACLcBGAs/s400/img2.png" width="400" /></a></div><div><br /></div><div>Luego hacemos clic en atributos de la Grilla Interactiva y colocamos el siguiente código en la sección de Advanced --&gt; "Javascript Initialization Code":</div><div><br /></div><div><div><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">function(config) {</span></div><div><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">&nbsp; config.initialSelection = false;</span></div><div><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">&nbsp; return config;</span></div><div><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">}</span></div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-n1sC8lIY6Wk/W1e6n2iW2dI/AAAAAAAAME4/4-Kh6N4IUfocrxVYRw_XjHDPWYG2WAf9ACLcBGAs/s1600/img3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="687" data-original-width="1600" height="171" src="https://3.bp.blogspot.com/-n1sC8lIY6Wk/W1e6n2iW2dI/AAAAAAAAME4/4-Kh6N4IUfocrxVYRw_XjHDPWYG2WAf9ACLcBGAs/s400/img3.png" width="400" /></a></div><div><br /></div><div>Guardamos y ejecutamos la página y podemos ver que ya no se muestra seleccionada la primera fila de nuestra grilla interactiva.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-Rp9ND6hnAZs/W1e6-IPBmCI/AAAAAAAAMFA/MptBpCSo1G0oytNbuhxbjrVpwXcr-6cPgCLcBGAs/s1600/img4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="543" data-original-width="1600" height="135" src="https://4.bp.blogspot.com/-Rp9ND6hnAZs/W1e6-IPBmCI/AAAAAAAAMFA/MptBpCSo1G0oytNbuhxbjrVpwXcr-6cPgCLcBGAs/s400/img4.png" width="400" /></a></div><div><br /></div><img src="http://feeds.feedburner.com/~r/DescubriendoElMundoDeOracle/~4/7JtaxgTpBFs" height="1" width="1" alt=""/> Clarisa J. Maman Orfali tag:blogger.com,1999:blog-1315583943401206186.post-6310851256070009539 Tue Jul 24 2018 19:52:00 GMT-0400 (EDT) "ORA-22902: CURSOR expression not allowed" in ORDS and APEX and how to fix them http://dgielis.blogspot.com/2018/07/ora-22902-cursor-expression-not-allowed.html <div class="separator" style="clear: both; text-align: left;">When you want to define different blocks of data, some hierarchical, some not, you can do that by using the <a href="https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/CURSOR-Expressions.html#GUID-B28362BE-8831-4687-89CF-9F77DB3698D2">cursor&nbsp;expressions</a>&nbsp;in SQL. An example of a query looks like this:</div><div class="separator" style="clear: both;"><br /></div><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">&nbsp; select</span><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">&nbsp; &nbsp; c.cust_first_name,</span><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">&nbsp; &nbsp; c.cust_last_name,</span><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">&nbsp; &nbsp; c.cust_city,</span><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">&nbsp; &nbsp;&nbsp;<span style="background-color: yellow;">cursor</span>(select o.order_total, order_name,</span><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span style="background-color: yellow;">cursor</span>(select p.product_name, i.quantity, i.unit_price</span><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;from demo_order_items i, demo_product_info p</span><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; where o.order_id = i.order_id</span><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; and i.product_id = p.product_id</span><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ) product &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;from demo_orders o</span><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; where c.customer_id = o.customer_id</span><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ) orders</span><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">&nbsp; from demo_customers c</span><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;"><br /></span><div class="separator" style="clear: both; text-align: left;">In the above query you see you can nest the cursor expressions. But you can also define the cursors next to each other. We use this technique a lot when defining where the data comes from in the <a href="https://www.apexofficeprint.com/">APEX Office Print</a>&nbsp;(AOP)&nbsp;APEX plugin:</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-Pa2n2AO0rao/W1ZDY3nbS5I/AAAAAAAAJXk/_lvlS8hp8XwJBxGAJWIm_GNnqYNtOJl0QCLcBGAs/s1600/Screen%2BShot%2B2018-07-23%2Bat%2B23.06.28.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="825" data-original-width="1600" height="330" src="https://4.bp.blogspot.com/-Pa2n2AO0rao/W1ZDY3nbS5I/AAAAAAAAJXk/_lvlS8hp8XwJBxGAJWIm_GNnqYNtOJl0QCLcBGAs/s640/Screen%2BShot%2B2018-07-23%2Bat%2B23.06.28.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">In <a href="https://apex.oracle.com/">Oracle Application Express</a> 18.1 there's a small bug (Bug 28298260 - REGRESSION: SQL QUERY CONTAINING CURSOR EXPRESSION CAN'T BE PARSED) that when you validate the query you get "ORA-22902: CURSOR expression not allowed".</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">The APEX Dev team already fixed it - you can download from <a href="https://support.oracle.com/">Oracle Support</a> the bundle PSE patch #28128115. Once applied everything is validating correctly again.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">AOP also supports REST web services, and some people define those in ORDS (Oracle REST Data Services). Depending the version of ORDS you might get the same error: "Error during evaluation of resource template: GET test/cursor/, SQL Error Code: 22,902, SQL Error Message: ORA-22902: CURSOR expression not allowed"</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-4keuH609B_Y/WQDtnPH_xbI/AAAAAAAAIrc/yrhS180hYe4KzetOvKbzwxZ6tDXIIb8AQCLcB/s1600/ords_error_cursor.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="114" src="https://3.bp.blogspot.com/-4keuH609B_Y/WQDtnPH_xbI/AAAAAAAAIrc/yrhS180hYe4KzetOvKbzwxZ6tDXIIb8AQCLcB/s640/ords_error_cursor.png" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-8mTV3UOoFew/WQDtm54hMKI/AAAAAAAAIrg/rVS5dOSQlosrHdfHWzUDFKU9U7SBd1KzQCLcB/s1600/ords_pagination.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="238" src="https://4.bp.blogspot.com/-8mTV3UOoFew/WQDtm54hMKI/AAAAAAAAIrg/rVS5dOSQlosrHdfHWzUDFKU9U7SBd1KzQCLcB/s640/ords_pagination.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both;">This doesn't mean your environment can not use the cursor syntax, you just have to set the pagination size to 0 and it's fixed.</div><br />In the latest version of ORDS (18.2) you get by default the 500 error without the error number:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-XRcq27NJgCI/W1ZCZClPilI/AAAAAAAAJXc/yk9N_qeLCL8ifPIWWuZ9GZAV6FlOlR9cQCLcBGAs/s1600/Screen%2BShot%2B2018-07-23%2Bat%2B22.58.46.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="358" data-original-width="1546" height="148" src="https://3.bp.blogspot.com/-XRcq27NJgCI/W1ZCZClPilI/AAAAAAAAJXc/yk9N_qeLCL8ifPIWWuZ9GZAV6FlOlR9cQCLcBGAs/s640/Screen%2BShot%2B2018-07-23%2Bat%2B22.58.46.png" width="640" /></a></div><br />Fix is the same, set pagination to 0 and you are good to go.<br /><br /> Dimitri Gielis tag:blogger.com,1999:blog-21122514.post-3738275402656012377 Tue Jul 24 2018 07:18:00 GMT-0400 (EDT) Five Minute Drills http://acitemreh.blogspot.com/2018/07/five-minute-drills.html &nbsp; At KScope there is an APEX event.&nbsp; "Open mic night"&nbsp; if you have something to show you get up to 5 minutes to show it.&nbsp; That isn't the only rule but it is an interesting challenge.&nbsp;<br />&nbsp; When I posted my last video on Relay Workflow I got a lot of really good feedback and a couple pieces of advice.&nbsp; First, try to limit video time to 5 minutes.&nbsp; Second, show us how it works not the extra details yet. <br />&nbsp; So I ditched the slides and took the challenge to show off Relay in 5-minute Drills.&nbsp; The first of which are up on youtube now.&nbsp; This was less than easy.&nbsp; The initial steps required to register, connect and integrate are pretty easy but still could not be contained to 5 minutes.&nbsp; It was a good exercise though and really makes you think about process and delivery in more detail.<br /><br /><br />&nbsp; I had to break it up into two Drills and the second ran over, but I wanted to complete the thought.&nbsp; The new videos are located at the following links:<br /><ul><li><a href="https://youtu.be/_0H0j5zcmy0" target="_blank">Before 'Hello' Part I&nbsp;</a>&nbsp;</li><ul><li><a href="https://gitlab.com/jaughenbaugh/relay_wf_pub/wikis/5md_bh01" target="_blank">Written Instructions</a></li></ul><li><a href="https://youtu.be/yGiYB6Fuydw" target="_blank">Before 'Hello' Part II</a></li><ul><li><a href="https://gitlab.com/jaughenbaugh/relay_wf_pub/wikis/5md_bh02" target="_blank">Written Instructions</a>&nbsp; </li></ul></ul>&nbsp; So, the next installment is in, and I am one more step closer to releasing Relay for those that want to try it out on <a href="http://apex.oracle.com/">apex.oracle.com</a><br /><br />&nbsp; Til then, Cheers!<br /><br /><br /> Jason D. Aughenbaugh tag:blogger.com,1999:blog-21645351.post-2724328864560518659 Sat Jul 21 2018 19:30:00 GMT-0400 (EDT) Hide certain objects on an APEX page http://dgielis.blogspot.com/2018/07/hide-certain-objects-on-apex-page.html A few days ago I got a question on how to hide the title row from the Interactive Report Pivot view.<br />So the person didn't want to show the red area:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-bdPVHhSYtWM/W1Oux_CVpLI/AAAAAAAAJWU/vhqSsNr54w48x11BOcWt908A3Jnen0gygCEwYBhgL/s1600/Screen%2BShot%2B2018-07-22%2Bat%2B00.04.17.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="915" data-original-width="1600" height="364" src="https://3.bp.blogspot.com/-bdPVHhSYtWM/W1Oux_CVpLI/AAAAAAAAJWU/vhqSsNr54w48x11BOcWt908A3Jnen0gygCEwYBhgL/s640/Screen%2BShot%2B2018-07-22%2Bat%2B00.04.17.png" width="640" /></a></div><br />The solution to this problem is to add the following&nbsp;CSS to your page:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-KDphZ11-on0/W1OuxkBcu2I/AAAAAAAAJWQ/gxdoJ8Qw3_kMxtsuMdSTzPJCy4kQWhteACEwYBhgL/s1600/Screen%2BShot%2B2018-07-22%2Bat%2B00.05.00.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="479" data-original-width="1042" height="292" src="https://4.bp.blogspot.com/-KDphZ11-on0/W1OuxkBcu2I/AAAAAAAAJWQ/gxdoJ8Qw3_kMxtsuMdSTzPJCy4kQWhteACEwYBhgL/s640/Screen%2BShot%2B2018-07-22%2Bat%2B00.05.00.png" width="640" /></a></div><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">table.a-IRR-table--pivot tr:nth-child(3) {</span><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">&nbsp; &nbsp; display:none;</span><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">}</span><br /><br />The result is this - the title is gone:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-8b4k8Jr_WUM/W1Oux3UOsxI/AAAAAAAAJWo/yCSwOsh3KTMEa8KJDN7o9azaW0VhXDfwgCEwYBhgL/s1600/Screen%2BShot%2B2018-07-22%2Bat%2B00.04.43.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="731" data-original-width="1600" height="292" src="https://2.bp.blogspot.com/-8b4k8Jr_WUM/W1Oux3UOsxI/AAAAAAAAJWo/yCSwOsh3KTMEa8KJDN7o9azaW0VhXDfwgCEwYBhgL/s640/Screen%2BShot%2B2018-07-22%2Bat%2B00.04.43.png" width="640" /></a></div><br />Doing this blog post is not about giving the solution to the above problem. I find it more important to show you the process to come to your answer. It comes down to find the right elements on the page which you can manipulate with CSS or JavaScript. To hide something, you can either use CSS with display: none or a JavaScript function (or JQuery hide()). The first thing you do is a search for the element. You want to use the Developer Tools of your browser for that. Most of the time you can right click on your page and do Inspect Element. The browser will show the HTML that is behind what you see on the page.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-a1YjqbJs8z0/W1OuyaIYbDI/AAAAAAAAJWc/4JTEtC2voGcmXuL9yFvlxOOvBg_V4nsNQCLcBGAs/s1600/Screen%2BShot%2B2018-07-22%2Bat%2B00.05.24.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="986" data-original-width="1600" height="394" src="https://3.bp.blogspot.com/-a1YjqbJs8z0/W1OuyaIYbDI/AAAAAAAAJWc/4JTEtC2voGcmXuL9yFvlxOOvBg_V4nsNQCLcBGAs/s640/Screen%2BShot%2B2018-07-22%2Bat%2B00.05.24.png" width="640" /></a></div><br />In the above screenshot, I see that row is a TR in a Table.<br />So the next step is to find a way to select that element. Typically you would use the id or class tag and look that up. The TR in our case doesn't have any of those, so I went up a line in the hierarchy until I find a good selector. The table has a class a-IRR-table--pivot which we can use.<br />Once we have the selector, we want to go to the real element, so we navigate back down. Now you need to know a bit of JavaScript or CSS or search on the internet how to do that. You can add elements after each other and it will drill down in the hierarchy again.<br />In our case, the TR is the third TR in the table, and there's a function to select that, which I used in CSS (nth-child).<br /><br />If this is all new to you, learning about JavaScript and CSS selectors is a great start. For example, <a href="https://www.w3schools.com/Css/css_display_visibility.asp">W3School</a> is a nice site to get started learning more about HTML, CSS, JavaScript, and general web.<br /><br /><br />Note that in Oracle APEX, you can also use a dynamic action to hide or show certain elements. A dynamic action is a declarative way to do JavaScript, so when you use the Hide / Show in a dynamic action, behind the scenes it will do the necessary call for you. If the item or region is not known for APEX you would use the same technique as I described above to find the right element which you can reference in the dynamic action with a JavaScript selector (. for class # for id).<br />Typically doing something with CSS is more performant than doing it with JavaScript, but it all depends on your use case what technique makes sense to use. Dimitri Gielis tag:blogger.com,1999:blog-21122514.post-2328034051094469326 Sat Jul 21 2018 18:20:00 GMT-0400 (EDT) The importance of being aliased http://oraclequirks.blogspot.com/2018/07/the-importance-of-being-aliased.html Byte64 tag:blogger.com,1999:blog-18037024.post-3497296899139809990 Fri Jul 20 2018 04:57:00 GMT-0400 (EDT) Removing Prior Versions of APEX in a PDB http://jastraub.blogspot.com/2018/07/removing-prior-versions-of-apex-in-pdb.html <span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><a href="https://twitter.com/dgielis" target="_blank">Dimitri Gielis</a> discovered a possible gap in our Application Express Installation Guide about removing prior versions of APEX, when APEX is installed locally in a PDB. If you follow our recommendation to remove the prior version of APEX after a successful upgrade to APEX 18.1, you might run into something similar to the following:</span><br /><br /><div class="" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; text-size-adjust: auto;"><span class="" style="font-family: &quot;courier new&quot;;">SQL&gt; alter session set container=APEX18;</span></div><div class="" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; text-size-adjust: auto;"><span class="" style="font-family: &quot;courier new&quot;;"><br class="" /></span></div><div class="" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; text-size-adjust: auto;"><span class="" style="font-family: &quot;courier new&quot;;">Session altered.</span></div><div class="" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; text-size-adjust: auto;"><span class="" style="font-family: &quot;courier new&quot;;"><br class="" /></span></div><div class="" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; text-size-adjust: auto;"><span class="" style="font-family: &quot;courier new&quot;;">SQL&gt; SELECT username</span></div><div class="" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; text-size-adjust: auto;"><span class="" style="font-family: &quot;courier new&quot;;">&nbsp;&nbsp;FROM dba_users&nbsp;</span></div><div class="" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; text-size-adjust: auto;"><span class="" style="font-family: &quot;courier new&quot;;">&nbsp;WHERE (&nbsp;&nbsp;username LIKE 'FLOWS\_______' ESCAPE '\'</span></div><div class="" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; text-size-adjust: auto;"><span class="" style="font-family: &quot;courier new&quot;;">&nbsp; &nbsp; &nbsp; &nbsp;OR username LIKE 'APEX\_______' ESCAPE '\' )</span></div><div class="" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; text-size-adjust: auto;"><span class="" style="font-family: &quot;courier new&quot;;">&nbsp; &nbsp;AND username NOT IN ( SELECT schema</span></div><div class="" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; text-size-adjust: auto;"><span class="" style="font-family: &quot;courier new&quot;;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;FROM dba_registry</span></div><div class="" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; text-size-adjust: auto;"><span class="" style="font-family: &quot;courier new&quot;;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;WHERE comp_id = 'APEX' );&nbsp;&nbsp;2&nbsp; &nbsp;&nbsp;3&nbsp; &nbsp;&nbsp;4&nbsp; &nbsp;&nbsp;5&nbsp; &nbsp;&nbsp;6&nbsp; &nbsp;&nbsp;7&nbsp;&nbsp;</span></div><div class="" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; text-size-adjust: auto;"><span class="" style="font-family: &quot;courier new&quot;;"><br class="" /></span></div><div class="" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; text-size-adjust: auto;"><span class="" style="font-family: &quot;courier new&quot;;">USERNAME</span></div><div class="" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; text-size-adjust: auto;"><span class="" style="font-family: &quot;courier new&quot;;">--------------------------------------------------------------------------------------------------------------------------------</span></div><div class="" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; text-size-adjust: auto;"><span class="" style="font-family: &quot;courier new&quot;;">APEX_050100</span></div><div class="" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; text-size-adjust: auto;"><span class="" style="font-family: &quot;courier new&quot;;"><br class="" /></span></div><div class="" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; text-size-adjust: auto;"><span class="" style="font-family: &quot;courier new&quot;;">SQL&gt; DROP USER APEX_050100 CASCADE;</span></div><div class="" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; text-size-adjust: auto;"><span class="" style="font-family: &quot;courier new&quot;;">DROP USER APEX_050100 CASCADE</span></div><div class="" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; text-size-adjust: auto;"><span class="" style="font-family: &quot;courier new&quot;;">*</span></div><div class="" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; text-size-adjust: auto;"><span class="" style="font-family: &quot;courier new&quot;;">ERROR at line 1:</span></div><div class="" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; text-size-adjust: auto;"><span class="" style="font-family: &quot;courier new&quot;;">ORA-28014: cannot drop administrative users</span></div><div class="" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; text-size-adjust: auto;"><span class="" style="font-family: &quot;courier new&quot;;"><br /></span></div><div class="" style="caret-color: rgb(0, 0, 0); text-size-adjust: auto;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">You would encounter this error if you followed section "<a href="https://docs.oracle.com/database/apex-18.1/HTMIG/performing-post-installation-tasks-for-upgrade-installations.htm#HTMIG-GUID-873974DC-E199-4FE0-BBBE-7FD5A6B75465" target="_blank">4.14.3 Removing Schemas from Prior Installations</a>" in the Installation Guide. The section you actually need to follow is "<a href="https://docs.oracle.com/database/apex-18.1/HTMIG/performing-post-installation-tasks-for-upgrade-installations.htm#HTMIG-GUID-873974DC-E199-4FE0-BBBE-7FD5A6B75465" target="_blank">4.14.4 Removing Schemas from Prior Installations in a CDB</a>." Now, you may argue that since APEX is installed locally, you are not installed in a CDB. But you actually are. You just don't have APEX installed in CDB$ROOT, but your database architecture is still a CDB. You need to use catcon.pl to drop the Oracle Maintained APEX_050100 schema like the following example:</span></div><div class="" style="caret-color: rgb(0, 0, 0); text-size-adjust: auto;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><br /></span></div><div class="" style="caret-color: rgb(0, 0, 0); text-size-adjust: auto;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"></span><br /><div class="" style="text-size-adjust: auto;"><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">$ORACLE_HOME/perl/bin/perl -I $ORACLE_HOME/rdbms/admin $ORACLE_HOME/rdbms/admin/catcon.pl -b drop_apex050100 -- --x'drop user APEX_050100 cascade'</span></div><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"></span><div><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><br /></span></div><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"></span></div><div class="" style="caret-color: rgb(0, 0, 0); text-size-adjust: auto;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><br /></span></div><div class="" style="caret-color: rgb(0, 0, 0); text-size-adjust: auto;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">The command above though will run in every container, or PDB, in the CDB. In some containers, APEX_050100 will not exist, and you will see an error in the catcon logs. Also, you may only want to drop the APEX_050100 schema from a particular PDB. There is the gap in the documentation, and what we need to add to the next version. In my case, my PDB was called APEX18, so to drop APEX_050100 only in the APEX18 PDB, the command would be: </span></div><div><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><br /></span></div><div><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">$ORACLE_HOME/perl/bin/perl -I $ORACLE_HOME/rdbms/admin $ORACLE_HOME/rdbms/admin/catcon.pl -b drop_apex050100 -c 'APEX18' -- --x'drop user APEX_050100 cascade' </span><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;"><br /></span><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">We will add this example as well as try and make the section title and lead in more clear in the next version of the Installation Guide.</span></div> Jason Straub tag:blogger.com,1999:blog-6139250371277978964.post-2887846067396307627 Thu Jul 19 2018 13:15:00 GMT-0400 (EDT) Set APEX application name for Dev, Test and Prod environment in the same database https://www.apex-at-work.com/2018/07/set-apex-application-name-for-dev-test.html In case you have a small application where development, test and maybe also production environment are on the same database and your applications in this environment distinguish only by the application IDs. To setup a custom application name based on the ID you could do like this:<br /><br /><br />We assume our application name is "Training room app" defined in the "Shared Components" &gt; "User Interface Attributes"<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-pmHi_Oe-xVk/W08pTbbSx7I/AAAAAAAAB-o/MQM-L88DPzAWpOKMetatnoMRMnNYAUMuQCLcBGAs/s1600/Edit_User_Interfaces.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="183" data-original-width="709" height="102" src="https://2.bp.blogspot.com/-pmHi_Oe-xVk/W08pTbbSx7I/AAAAAAAAB-o/MQM-L88DPzAWpOKMetatnoMRMnNYAUMuQCLcBGAs/s400/Edit_User_Interfaces.png" width="400" /></a></div><br />To differentiate the environments I add a dynamic action "Page Load" on Page 0.<br />This dynamic action is executing custom Javascript code:<br /><br /><span style="font-family: &quot;Courier New&quot;, Courier, monospace;">if ('&amp;APP_ID.' == '200') {<br />&nbsp; $('.t-Header-logo').find('span').html('<span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">Training room app - </span>&lt;b style="color:#008A34"&gt;<span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">Test Environment</span>&lt;/b&gt;');<br />}<br />else if ('&amp;APP_ID.' == '300') {<br />&nbsp; $('.t-Header-logo').find('span').html('<span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">Training room app - </span>&lt;b style="color:#9366a5"&gt;Development Environment&lt;/b&gt;');<br />}</span><br /><br /><span style="font-family: inherit;">The code is changing the name of the </span>logo area.<br /><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;">&nbsp;<a href="https://1.bp.blogspot.com/-YvD3DlzR27k/W08sPoWWx6I/AAAAAAAAB-4/FEb1a0x77M0j0iZRQK8t3xAFLACP3rjzACLcBGAs/s1600/2017_07883_-_Merseburg_-_NeTRaCE_-_Auftragsdatenbank.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="40" data-original-width="478" height="32" src="https://1.bp.blogspot.com/-YvD3DlzR27k/W08sPoWWx6I/AAAAAAAAB-4/FEb1a0x77M0j0iZRQK8t3xAFLACP3rjzACLcBGAs/s400/2017_07883_-_Merseburg_-_NeTRaCE_-_Auftragsdatenbank.png" width="400" /></a></div><br /> Tobias Arnhold tag:blogger.com,1999:blog-6481483192141562388.post-1690464316753543927 Wed Jul 18 2018 08:05:00 GMT-0400 (EDT) fun with calendars and dates https://svenweller.wordpress.com/2018/07/17/fun-with-calendars-and-dates/ <h1>Intro</h1> <figure data-shortcode="caption" id="attachment_7848" style="width: 184px" class="wp-caption alignright"><img data-attachment-id="7848" data-permalink="https://svenweller.wordpress.com/2018/07/17/fun-with-calendars-and-dates/1911_ottoman_calendar/" data-orig-file="https://svenweller.files.wordpress.com/2018/07/1911_ottoman_calendar.jpg?w=184&#038;h=314" data-orig-size="600,1026" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="1911_Ottoman_Calendar" data-image-description="" data-medium-file="https://svenweller.files.wordpress.com/2018/07/1911_ottoman_calendar.jpg?w=184&#038;h=314?w=175" data-large-file="https://svenweller.files.wordpress.com/2018/07/1911_ottoman_calendar.jpg?w=184&#038;h=314?w=599" class=" wp-image-7848 alignright" src="https://svenweller.files.wordpress.com/2018/07/1911_ottoman_calendar.jpg?w=184&#038;h=314" alt="1911_Ottoman_Calendar" width="184" height="314" srcset="https://svenweller.files.wordpress.com/2018/07/1911_ottoman_calendar.jpg?w=184&amp;h=314 184w, https://svenweller.files.wordpress.com/2018/07/1911_ottoman_calendar.jpg?w=368&amp;h=628 368w, https://svenweller.files.wordpress.com/2018/07/1911_ottoman_calendar.jpg?w=88&amp;h=150 88w, https://svenweller.files.wordpress.com/2018/07/1911_ottoman_calendar.jpg?w=175&amp;h=300 175w" sizes="(max-width: 184px) 100vw, 184px" /><figcaption class="wp-caption-text">By <span lang="en">Unknown</span> &#8211; 1911 Ottoman calendar, Public Domain, <a href="https://commons.wikimedia.org/w/index.php?curid=49731299">Link</a></figcaption></figure> <p>Calendar and date arithmetic is not easy. And not because of the database, but because the stuff exists in the real word. The database does an excellent job to reflect many or most of the strange attributes that calendar systems have.</p> <p>Here is a collection of surprising, quirky or interesting things around usage of date and time values in an Oracle database. A lot of those things have nothing to do with the database, but instead with the complexity of the world.</p> <p>By examining those edge cases we might learn something about the general workings of dates, calendars and the Oracle database.</p> <h1>5 Fun Facts</h1> <h2>1) We live in the year 2561</h2> <pre class="brush: sql; light: true; title: ; notranslate"> alter session set nls_calendar = 'THAI BUDDHA'; select to_char(sysdate,'YYYY') as current_year from dual; </pre> <p><code>CURRENT_YEAR<br /> 2561<br /> </code><br /> q.e.d.</p> <p>Reason of cause is that there are other calendars out there in the world, not only the default Gregorian one. And according to the <a href="https://en.wikipedia.org/wiki/Buddhist_calendar" target="_blank" rel="noopener">Thai Buddha calendar</a> we are now in 2561.</p> <h2>2) persons existed that were born on the 30th of february</h2> <p>&#8230;but only in Sweden some time ago.</p> <p>I got this from a source which doesn&#8217;t exist anymore. However here is a site that seem to have the same information stored:<br /> <a href="http://karaszi.com/the-ultimate-guide-to-the-datetime-datatypes" target="_blank" rel="noopener">the-ultimate-guide-to-the-datetime-datatypes</a></p> <blockquote><p>Why is 1753 the earliest date for datetime?<br /> Good question. It is for historical reasons. In what we sometimes refer to as the western world, we have had two calendars in modern time: the Julian and the Gregorian calendars. These calendars were a number of days apart (depending on which century you look at), so when a culture that used the Julian calendar moved to the Gregorian calendar, they dropped from 10 to 13 days. Great Britain made this shift in 1752 (1752-09-02 were followed by 1752-09-14). An educated guess why Sybase selected 1753 as earliest date is that if you were to store an earlier date than 1753, you would also have to know which country and also handle this 10-13 day jump. So they decided to not allow dates earlier than 1753. Note, however that other countries did the shift later than 1752. Turkey, for instance, did it as late as 1927.</p> <p>Being Swedish, I find it a bit amusing that Sweden had the weirdest implementation. They decided to skip the leap day over a period of 40 years (from 1700 to 1740), and Sweden would be in sync with the Gregorian calendar after 1740 (but meanwhile not in sync with anyone). However, in 1704 and 1708 the leap day wasn&#8217;t skipped for some reason, so in 1712 which was a leap year, they inserted yet an extra day (imagine being born in Feb 30!) and then did the shift over a day like everyone else, in 1753.</p></blockquote> <p>Does the database know about this? Lets find out:</p> <pre class="brush: sql; light: true; title: ; notranslate"> alter session set nls_date_language='SWEDISH'; alter session set nls_territory='SWEDEN'; select to_date('30-02-1712','dd-mm-YYYY') from dual; </pre> <pre style="color:red;">ORA-01839: date not valid for month specified</pre> <p>Using a date literal instead of TO_DATE doesn&#8217;t help either.</p> <pre class="brush: sql; light: true; title: ; notranslate"> select to_char(date '1712-02-30') from dual;</pre> <pre style="color:red;">ORA-01847: day of month must be between 1 and last day of month</pre> <p>So this doesn&#8217;t work. Why? Because the 30th of february only existed in the Julian Calendar System. The Oracle Database doesn&#8217;t support a Julian Calendar &#8211; we can not choose calendar systems, that are not in use anymore.</p> <p>Btw. the 29th of februar 1712 does exist. Even in Sweden.</p> <pre class="brush: sql; light: true; title: ; notranslate"> select to_char(date '1712-02-29','fmddth Month YYYY') from dual; </pre> <pre>29th Februari 1712</pre> <p>The article also briefly mentioned that Turkey was the last country to switch to the Gregorian Calendar. Before that, they had the <a href="https://en.wikipedia.org/wiki/Rumi_calendar" target="_blank" rel="noopener">Rumi Calendar</a>, which is a variation of Julian. It differs mostly about the starting year.</p> <p>Turkey did the switch as late as 1927. After the <strong>15th February</strong> 1332 <a href="https://en.wikipedia.org/wiki/Hijri_year" target="_blank" rel="noopener">AH</a> (Rumi) they skipped 13 days, so that the next day was the <strong>1st March</strong> 1927 AD (Gregorian). And they switched the year too.</p> <p>Again, if we ask the database then it does not know about this gap. </p> <pre class="brush: sql; light: true; title: ; notranslate"> set pagesize 100 alter session set nls_date_language='TURKISH'; alter session set nls_territory='TURKEY'; -- 28 days later... with twentyeight as (select level lv from dual connect by level &lt;=28) select to_char(date &#039;1927-02-10&#039; + lv,&#039;fmddth Month YYYY&#039;) from twentyeight; </pre> <pre>11th Şubat 1927 12th Şubat 1927 13th Şubat 1927 14th Şubat 1927 15th Şubat 1927 <em>16th Şubat 1927 17th Şubat 1927 18th Şubat 1927 19th Şubat 1927 20th Şubat 1927 21st Şubat 1927 22nd Şubat 1927 23rd Şubat 1927 24th Şubat 1927 25th Şubat 1927 26th Şubat 1927 27th Şubat 1927 28th Şubat 1927</em> 1st Mart 1927 2nd Mart 1927 3rd Mart 1927 4th Mart 1927 5th Mart 1927 6th Mart 1927 7th Mart 1927 </pre> <p>Since the leaped days existed in the Gregorian Calendar, there is no reason to leave them out.</p> <p>Interestingly in Turkey there should still be living persons that were born in or before 1332!<br /> (older than 92 years)</p> <h2>3) There are no days between 4 Oct 1582 and 15 Oct 1582</h2> <pre class="brush: sql; light: true; title: ; notranslate">select to_char(date '1582-10-4','ddth Mon YYYY') from dual; </pre> <pre>04th Oct 1582</pre> <p>+1 day</p> <pre class="brush: sql; light: true; title: ; notranslate">select to_char(date '1582-10-4' + 1,'ddth Mon YYYY') from dual; </pre> <pre>15th Oct 1582</pre> <p>04th Oct 1582 + 1 = 15th Oct 1582 ?</p> <p>After the previous chapter the reason should be obvious.<br /> At this time the Gregorian calendar leapt 10 days in order to catch up with the astronomical year. </p> <p>From <a href="http://www.unc.edu/~rowlett/units/dictY.html#year" rel="nofollow">http://www.unc.edu/~rowlett/units/dictY.html#year</a></p> <blockquote><p> <strong>year (a or y or yr) [2]</strong><br /> a traditional unit of time usually equal to 365 or 366 days. We need a whole number of days for the calendar year used in ordinary life. Ancient astronomers knew that the year [1] is approximately 365 days long, and we now know the correct figure is approximately 365.242 days. If we use 365 as the number of days in every calendar year, the extra 0.242 day adds up quickly and causes large errors in predicting the seasons. To solve this problem, the Roman emperor Julius Caesar decreed in 46 BC that the calendar year should have 365 days generally, but that every fourth year should have an extra, or 366th, day. The longer year is called a leap year. In this Julian calendar, four years equal exactly 1461 days, so the average Julian year is exactly 365.25 days.</p> <p> This was a big step toward accuracy in the calendar, but the Julian year is too long by 0.008 day, or a little over 11 minutes. By the time of the Renaissance, these 11-minute errors had accumulated to a total error of about 10 days (since the Council of Nicaea in 325 AD, which set the rules for deciding when Easter should be celebrated). The spring equinox was occurring near March 11 instead of March 21. In 1582, <strong>Pope Gregory XIII decreed that 10 days should be dropped from the calendar: the day after 1582 October 4 was October 15</strong>. To reduce future errors, the pope further decreed that years divisible by 100 are not leap years unless they are also divisible by 400. Thus 2000 and 2400 are leap years, but 2100, 2200, and 2300 are not. It took many years, but the Gregorian calendar has now been accepted as the civil calendar in all countries of the world.</p> <p> With the Gregorian adjustment, there are exactly 146 097 days in every 400 years, and the average Gregorian year is exactly 365.2425 days. The Gregorian year is still too long, but by less than half a minute. It will take thousands of years for this error to accumulate to 1 day, so the calendar year and the tropical year are in good enough agreement to last us a long time.</p></blockquote> <p>And this time, the database with its default Gregorian calendar knows about it!</p> <p>Database considers days that seem to be inside this gap, as if they were after the leaped days.</p> <pre class="brush: sql; light: true; title: ; notranslate">select to_char(date '1582-10-5','ddth Mon YYYY') from dual; </pre> <pre>15th Oct 1582</pre> <h2>4) The north pole and the south pole are on different time zones</h2> <p>From wikipedia: <a href="https://simple.wikipedia.org/wiki/Time_zone" rel="nofollow">https://simple.wikipedia.org/wiki/Time_zone</a></p> <blockquote><p>In the poles, the time is <strong>UTC </strong>in the North Pole and <strong>UTC+12</strong> in the South Pole.</p></blockquote> <p>(and no this is not the &#8220;South Pole, Illinois, USA&#8221; nor the &#8220;North Pole, New South Wales, Australia&#8221;)</p> <p>So in case you happen to live or work at the south pole, set your session time zone to UTC+12.</p> <p>Let me simulate that for you:</p> <pre class="brush: sql; light: true; title: ; notranslate"> col sessiontimezone format A20 col dbtimezone format A20 -- check current settings select sessiontimezone, tz_offset(sessiontimezone), dbtimezone, tz_offset(dbtimezone) from dual; </pre> <pre>SESSIONTIMEZONE TZ_OFFS DBTIMEZONE TZ_OFFS -------------------- ------- -------------------- ------- Europe/Berlin +02:00 +02:00 +02:00</pre> <p>Currently I&#8217;m in Frankfurt which is the same time zone as Berlin, so 2 hours before UTC.<br /> Since I have to do some quick work at the south pole, let&#8217;s change my session settings to reflect that.</p> <pre class="brush: sql; light: true; title: ; notranslate"> -- change to UTC+12 alter session set time_zone ='+12:00'; </pre> <pre>Session altered.</pre> <pre class="brush: sql; light: true; title: ; notranslate"> -- how late is it here currently? select sysdate, current_date from dual; </pre> <pre>SYSDATE CURRENT_DATE ----------------- ----------------- 17.07.18 10:51:12 17.07.18 20:51:12 </pre> <p>So here at the south pole, it is almost 9 p.m. whereas the database is still in Frankfurt at 11 a.m.</p> <p>After enjoying The Great White Silence I need to return.</p> <pre class="brush: sql; light: true; title: ; notranslate"> -- change back to original alter session set time_zone=local; </pre> <pre>Session altered.</pre> <pre class="brush: sql; light: true; title: ; notranslate"> -- doublecheck settings select sessiontimezone, tz_offset(sessiontimezone), dbtimezone, tz_offset(dbtimezone) from dual; </pre> <pre>SESSIONTIMEZONE TZ_OFFS DBTIMEZONE TZ_OFFS -------------------- ------- -------------------- ------- Europe/Berlin +02:00 +02:00 +02:00</pre> <p>It is good to be back! Timezone travelling is exhausting.</p> <h2>5) The word calendar comes from the Latin word Kalendae which meant the first day of the month</h2> <p>A calendar is essentially a list of first month days.</p> <p>Getting the first day of a month is easy.</p> <pre class="brush: sql; light: true; title: ; notranslate">trunc(sysdate,'MM') =&gt; 1st of the current month.</pre> <p>But what about the first day of a week? And which week are we in?</p> <p>This is complex for two major reasons. There is quite some confusion about when does a week start and what is the first week in the year. And with confusion I mean, different countries have different rules for that.</p> <p><a href="https://www.calendar-week.org/" rel="nofollow">https://www.calendar-week.org/</a></p> <p>The good thing is, the Oracle database has all this knowledge. A developer just has to understand it. As usual NLS settings will influence the behaviour.</p> <p>Different date formats refer to those NLS settings.</p> <p>&#8216;D&#8217; returns the number of the day inside the week.</p> <p>&#8216;WW&#8217; returns the number of the week inside the year. Week 1 starts on the first day of the year and continues to the seventh day of the year.<br /> &#8216;IW&#8217; returns the number of the ISO-week.</p> <p>&#8216;YYYY&#8217; refers to the year<br /> &#8216;IYYY&#8217; refers the ISO-year.</p> <p><strong>some examples</strong></p> <p><em>What weekday is the first day of the week?<br /> </em></p> <p>NLS_TERRITORY influences what the first day of a week is.</p> <pre class="brush: sql; light: true; title: ; notranslate"> alter session set NLS_DATE_LANGUAGE = 'AMERICAN'; alter session set NLS_TERRITORY = 'AMERICA'; select to_char(trunc(sysdate,'D'),'Day') as "First Day in America" from dual; alter session set NLS_TERRITORY = 'GERMANY'; select to_char(trunc(sysdate,'D'),'Day') as "First Day in Germany" from dual; alter session set NLS_TERRITORY = 'IRAQ'; select to_char(trunc(sysdate,'D'),'Day') as "First Day in Iraq" from dual; select to_char(trunc(sysdate,'IW'),'Day') as "ISO First Day" from dual; </pre> <p>result</p> <pre>Session altered. Session altered. First Day in America --------- Sunday Session altered. First Day in Germany --------- Monday Session altered. First Day in Iraq --------- Saturday ISO First Day --------- Monday </pre> <p>NLS_TERRITORY does not directly influence what the first week in the year is! To get the week we always use formatter options (IW or WW) that directly decide, which week logic needs to be applied.</p> <p>However NLS_TERRITORY sets an ISO-Week flag. Unfortunately this is <a href="https://docs.oracle.com/en/database/oracle/oracle-database/12.2/nlspg/setting-up-globalization-support-environment.html#GUID-81324318-EFC8-457B-B01F-5BC8B37DEEA5" target="_blank" rel="noopener">not well documented</a>. I believe this flag is partially responsible for one of the behaviours mentioned in the &#8220;Stranger Things&#8221; section.</p> <h1>5 Stranger Things &#8211; bug or feature?</h1> <p><a title="By Lowtrucks [CC BY-SA 4.0 (https://creativecommons.org/licenses/by-sa/4.0 ) or Public domain], from Wikimedia Commons" href="https://commons.wikimedia.org/wiki/File:Stranger_Things_logo.png"><img width="512" alt="Stranger Things logo" src="https://upload.wikimedia.org/wikipedia/commons/3/38/Stranger_Things_logo.png"></a></p> <h2>1) sysdate returns a date, but systimestamp does not return a timestamp</h2> <p>systimestamp returns a <em>timestamp with timezone</em>. Localtimestamp would be the function that returns a <em>timestamp</em>. In many cases systimestamp still is the best option to use!</p> <p>These are the DATATYPES : pseudocolumns dealing with points in time.</p> <ul> <li>DATE : sysdate, current_date</li> <li>TIMESTAMP : localtimestamp</li> <li>TIMESTAMP WITH TIME ZONE : systimestamp, current_timestamp</li> <li>TIMESTAMP WITH LOCAL TIME ZONE</li> </ul> <p>example<br /> First modify the session so that session timezone and db timezone differs.</p> <pre>ALTER SESSION SET TIME_ZONE='+10:00'; show nls DB_TIMEZONE +01:00 SESSION_TIMEZONE +10:00 SESSION_TIMEZONE_OFFSET +10:00 </pre> <p>Check the pseudocolumns and convert them to timestamp if needed (using cast). The same would happen when the value is stored in a timestamp column. The database implicitly does the conversion.</p> <pre class="brush: sql; title: ; notranslate"> select to_char(sysdate,'DD-MM-RR HH24:MI:SS') as "sysdate", to_char(localtimestamp,'DD-MM-RR HH24:MI:SS') as "localTS", to_char(current_timestamp,'DD-MM-RR HH24:MI:SS TZH') as "currentTS", to_char(systimestamp,'DD-MM-RR HH24:MI:SS TZH') as "sysTS", to_char(cast(current_timestamp as timestamp),'DD-MM-RR HH24:MI:SS') as "currentTS_converted", to_char(cast(systimestamp as timestamp),'DD-MM-RR HH24:MI:SS') as "sysTS_converted" from dual; </pre> <p>Result (timestamp):</p> <pre>sysdate 16-07-18 15:01:58 localTS <span style="color:red;">16-07-18 23:01:58</span> currentTS 16-07-18 23:01:58 +10 sysTS 16-07-18 15:01:58 +02 currentTS_converted <span style="color:red;">16-07-18 23:01:58</span> sysTS_converted 16-07-18 15:01:58 </pre> <p>Note that localtimestamp and current_timestamp returns (and stores) a different hour than sysdate. Systimestamp returns the same hour after conversion and therefore matches sysdate.</p> <p>Better would be to have a column that stores the timezone information too. Either <em>timestamp with time zone</em> or <em>timestamp with local time zone</em>. Since TZ info is stored, it does not matter anymore which datatype has the source.</p> <pre class="brush: sql; title: ; notranslate"> select to_char(sysdate,'DD-MM-RR HH24:MI:SS') as "sysdate", to_char(localtimestamp,'DD-MM-RR HH24:MI:SS') as "localTS", to_char(current_timestamp,'DD-MM-RR HH24:MI:SS TZH') as "currentTS", to_char(systimestamp,'DD-MM-RR HH24:MI:SS TZH') as "sysTS", to_char(cast(localtimestamp as timestamp with local time zone),'DD-MM-RR HH24:MI:SS [TZR]') as "localTS_converted", to_char(cast(current_timestamp as timestamp with local time zone),'DD-MM-RR HH24:MI:SS [TZR]') as "currentTS_converted", to_char(cast(systimestamp as timestamp with local time zone),'DD-MM-RR HH24:MI:SS [TZR]') as "sysTS_converted" from dual; </pre> <p>Result (timestamp with local time zone):</p> <pre>sysdate 16-07-18 15:13:26 localTS 16-07-18 23:13:26 currentTS 16-07-18 23:13:26 +10 sysTS 16-07-18 15:13:26 +02 localTS_converted 16-07-18 23:13:26 [+10:00] currentTS_converted 16-07-18 23:13:26 [+10:00] sysTS_converted 16-07-18 23:13:26 [+10:00] </pre> <p>As we can see the result is always the same point <a href="https://en.wikipedia.org/wiki/In_Time" target="_blank">In Time</a>.</p> <h2>2) Micro Intervals</h2> <p>And of cause there are also datatypes that deal with durations.</p> <ul> <li>NUMBER</li> <li>INTERVAL YEAR TO MONTH</li> <li>INTERVAL DAY TO SECOND</li> </ul> <p>Why are there two interval types? Because those are independend measurement systems for a duration of time. And there is no correct conversion possible from one into the other.</p> <p>Consider this: 29 days (interval day to second) could be slightly less, slightly more or sometimes even exactly one 1 month (interval year to month). We can only do this conversion if we additionally have some reference point, like the starting day. Without this reference point in time, we can&#8217;t correctly convert from one system of measurement into the other.</p> <p>We can convert from number to interval using the functions numtoDSinterval or numtoYMinterval.</p> <p>Let&#8217;s do some workday calculations.</p> <p>My typical day of work is from (ok I might understate a bit) is from 9:30 to 18:30. </p> <pre class="brush: sql; light: true; title: ; notranslate">select to_date('18:30','HH24:MI') - to_date('9:30','HH24:MI') from dual;</pre> <pre>0.375 </pre> <p>A date minus a date returns a number. This is the result in days. So I worked for 0.375 days. Lets see that in interval format.</p> <pre class="brush: sql; light: true; title: ; notranslate">select numtoDSinterval(0.375, 'day') from dual;</pre> <pre>+00 09:00:00.000000</pre> <p>Looks about right!</p> <p>Can we also see that in a Month interval ? The MONTHS_BETWEEN functions gives us the result in number (= months) for the difference between two dates.</p> <pre class="brush: sql; light: true; title: ; notranslate"> select months_between(to_date('19:30','HH24:MI') ,to_date('10:30','HH24:MI')) from dual;</pre> <pre>0</pre> <p>Hm&#8230; 9 hours equal 0 months&#8230; </p> <p>Let&#8217;s assume somebody has a large shift requiring to work for more than 24 hours.</p> <pre class="brush: sql; light: true; title: ; notranslate">-- how many months did he work? select months_between(to_date('2018-07-02 19:30','YYYY-MM-DD HH24:MI') ,to_date('2018-07-01 07:15','YYYY-MM-DD HH24:MI')) from dual; </pre> <pre>0.0487231182795698924731182795698924731183</pre> <p>And as an interval&#8230;</p> <pre class="brush: sql; light: true; title: ; notranslate">select numtoYMinterval(0.0487, 'MONTH') from dual;</pre> <pre>+00-01</pre> <p>Hmm&#8230; 0.0488 Months =&gt; 0 Years 1 Month ?</p> <p>Is it always rounded up?</p> <p>So what would a larger result be:</p> <pre class="brush: sql; light: true; title: ; notranslate">select numtoYMinterval(1.0487, 'MONTH') from dual;</pre> <pre>+00-01</pre> <p>Hmm&#8230; 1.0487 Months =&gt; 0 Years 1 Month</p> <p>This time it is not rounded up, but rounded down.</p> <p>How about some more micro intervals?</p> <pre> numtoYMinterval(0.001, 'MONTH') =&gt; +00-00 numtoYMinterval(0.009, 'MONTH') =&gt; +00-00 numtoYMinterval(0.01, 'MONTH') =&gt; <span style="color:red;">+00-01</span> numtoYMinterval(0.49, 'MONTH') =&gt; <span style="color:red;">+00-01</span> numtoYMinterval(0.5, 'MONTH') =&gt; +00-01 numtoYMinterval(1.01, 'MONTH') =&gt; +00-01 numtoYMinterval(1.5, 'MONTH') =&gt; +00-02 numtoYMinterval(2.01, 'MONTH') =&gt; +00-02 numtoYMinterval(2.5, 'MONTH') =&gt; +00-03 </pre> <p>Result</p> <p>For very small values (0.01-0.49) numtoYMinterval rounds up, instead of rounding down. For larger values, the rounding is consistent. Those values are rounded down, as expected.</p> <p>This feature was implemented somewhere between Oracle DB version 10 and 11. It took me a while, but now it is accepted as a unpublished bug (26244914).</p> <p>Recommendation: <strong>Avoid numtoYMinterval</strong>. There are several strange edge cases with that function.</p> <h2>3) date format &#8220;J&#8221; &#8211; Julian</h2> <p>We can use the <a href="https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sqlrf/Format-Models.html#GUID-EAB212CF-C525-4ED8-9D3F-C76D08EEBC7A" target="_blank" rel="noopener">J format mask</a> to spell out numbers (Jsp).<br /> J is called Julian day; the number of days since January 1, 4712 BC.</p> <p>Let&#8217;s play around with it a little.</p> <pre class="brush: sql; light: true; title: ; notranslate">select to_char(sysdate,'J') from dual;</pre> <p>2458317</p> <p>Of cause when you execute it, you will get a different (larger) number. Time passed.</p> <p>We use this number and substract it from sysdate, then add the number of days we are interested in. This time using &#8220;sp&#8221; = spelling in the format parameter.</p> <pre class="brush: sql; light: true; title: ; notranslate">select to_char((sysdate-(2458317-5)),'Jsp') from dual</pre> <pre>Five</pre> <p>Cool! This way we can spell out any number. Unfortunatly this only works in English, not in other languages.</p> <p>Important side note: The calculation must be like this</p> <pre>sysdate-(2458317-5)</pre> <p>Although mathematically the same, this would have resulted in an error</p> <pre>(sysdate-2458317)+5</pre> <pre style="color:red;">ORA-01841: (full) year must be between -4713 and +9999, and not be 0</pre> <p>Problem is that the resulting date value is invalid (before the beginning of time).</p> <p>To avoid hardcoding 2458317, we can calculate it from sysdate.</p> <pre class="brush: sql; light: true; title: ; notranslate">select to_char(sysdate-(to_number(to_char(sysdate,'J'))-123),'Jsp') spell_number from dual; </pre> <pre>One Hundred Twenty-Three</pre> <p>Ok let&#8217;s try a large number&#8230;</p> <pre class="brush: sql; light: true; title: ; notranslate">select to_char(sysdate-(to_number(to_char(sysdate,'J'))-1721116),'Jsp') spell_number from dual </pre> <pre>One Million Seven Hundred Twenty Thousand Seven Hundred Fifty-One</pre> <p>And one more&#8230;</p> <pre class="brush: sql; light: true; title: ; notranslate">select to_char(sysdate-(to_number(to_char(sysdate,'J'))-1721117),'Jsp') spell_number from dual </pre> <pre style="color:red;">000000000000000000000000000000000000000000000000000000000000000000000000000000</pre> <p><a href="https://www.destroyallsoftware.com/talks/wat" target="_blank" rel="noopener">Wat</a>!? So spelling out <em>One Million Seven Hundred Twenty Thousand Seven Hundred Fifty-<strong>One</strong></em> is ok, but <em>One Million Seven Hundred Twenty Thousand Seven Hundred Fifty-<strong>Two</strong></em> not&#8230;</p> <p>Hold on a minute. Even the first number was not spelled correctly!<br /> 172<strong>1116</strong> != One Million Seven Hundred Twenty Thousand <strong>Seven Hundred Fifty-One</strong></p> <p>As so often there is a reason for that. The difference between both numbers is exactly 365. Which is our first clue. We need to understand which dates are we talking about. </p> <p><span style="font-size:small;">The following rows depend heavily on the database version it is running.</span></p> <p>This is from a 12.2.0.1 DB. For readability, I removed several hundred rows from the output.</p> <pre class="brush: sql; light: true; title: ; notranslate"> with testdata as (select level lv, 1721340-300+level days# from dual connect by level &lt;= 400) select lv, days#, to_char(sysdate-(to_number(to_char(sysdate,&#039;J&#039;))-days#),&#039;YYYY-MM-DD A.D.&#039;) dy, to_char(sysdate-(to_number(to_char(sysdate,&#039;J&#039;))-days#),&#039;J&#039;) Julian, to_char(sysdate-(to_number(to_char(sysdate,&#039;J&#039;))-days#),&#039;Jsp&#039;) spelled_number from testdata; </pre> <pre style="font-size:x-small;"> LV DAYS# DY JULIAN SPELLED_NUMBER 1 1721041 0001-12-15 B.C. 1721041 One Million Seven Hundred Twenty-One Thousand Forty-One 2 1721042 0001-12-16 B.C. 1721042 One Million Seven Hundred Twenty-One Thousand Forty-Two 3 1721043 0001-12-17 B.C. 1721043 One Million Seven Hundred Twenty-One Thousand Forty-Three 4 1721044 0001-12-18 B.C. 1721044 One Million Seven Hundred Twenty-One Thousand Forty-Four 5 1721045 0001-12-19 B.C. 1721045 One Million Seven Hundred Twenty-One Thousand Forty-Five 6 1721046 0001-12-20 B.C. 1721046 One Million Seven Hundred Twenty-One Thousand Forty-Six 7 1721047 0001-12-21 B.C. 1721047 One Million Seven Hundred Twenty-One Thousand Forty-Seven 8 1721048 0001-12-22 B.C. 1721048 One Million Seven Hundred Twenty-One Thousand Forty-Eight 9 1721049 0001-12-23 B.C. 1721049 One Million Seven Hundred Twenty-One Thousand Forty-Nine 10 1721050 0001-12-24 B.C. 1721050 One Million Seven Hundred Twenty-One Thousand Fifty 11 1721051 0001-12-25 B.C. 1721051 One Million Seven Hundred Twenty-One Thousand Fifty-One 12 1721052 0001-12-26 B.C. 1721052 One Million Seven Hundred Twenty-One Thousand Fifty-Two 13 1721053 0001-12-27 B.C. 1721053 One Million Seven Hundred Twenty-One Thousand Fifty-Three 14 1721054 0001-12-28 B.C. 1721054 One Million Seven Hundred Twenty-One Thousand Fifty-Four 15 1721055 0001-12-29 B.C. 1721055 One Million Seven Hundred Twenty-One Thousand Fifty-Five 16 1721056 0001-12-30 B.C. 1721056 One Million Seven Hundred Twenty-One Thousand Fifty-Six <span style="color:blue;">17 1721057 0001-12-31 B.C. 1721057 One Million Seven Hundred Twenty-One Thousand Fifty-Seven</span> 18 1721058 <span style="color:red;">0001-01-01 B.C. 1720693 One Million Seven Hundred Twenty Thousand Six Hundred Ninety-Three</span> 19 1721059 0001-01-02 B.C. 1720694 One Million Seven Hundred Twenty Thousand Six Hundred Ninety-Four 20 1721060 0001-01-03 B.C. 1720695 One Million Seven Hundred Twenty Thousand Six Hundred Ninety-Five 21 1721061 0001-01-04 B.C. 1720696 One Million Seven Hundred Twenty Thousand Six Hundred Ninety-Six 22 1721062 0001-01-05 B.C. 1720697 One Million Seven Hundred Twenty Thousand Six Hundred Ninety-Seven 23 1721063 0001-01-06 B.C. 1720698 One Million Seven Hundred Twenty Thousand Six Hundred Ninety-Eight 24 1721064 0001-01-07 B.C. 1720699 One Million Seven Hundred Twenty Thousand Six Hundred Ninety-Nine 25 1721065 0001-01-08 B.C. 1720700 One Million Seven Hundred Twenty Thousand Seven Hundred ... snip 1721066-1721112 no major change there... 73 1721113 0001-02-25 B.C. 1720748 One Million Seven Hundred Twenty Thousand Seven Hundred Forty-Eight 74 1721114 0001-02-26 B.C. 1720749 One Million Seven Hundred Twenty Thousand Seven Hundred Forty-Nine 75 1721115 0001-02-27 B.C. 1720750 One Million Seven Hundred Twenty Thousand Seven Hundred Fifty 76 1721116 0001-02-28 B.C. 1720751 One Million Seven Hundred Twenty Thousand Seven Hundred Fifty-One 77 1721117 <span style="color:red;">0000-00-00 0000 0000000 000000000000000000000000000000000000000000000000000000000000000000000000000000</span> 78 1721118 0001-03-01 B.C. 1720752 One Million Seven Hundred Twenty Thousand Seven Hundred Fifty-Two 79 1721119 0001-03-02 B.C. 1720753 One Million Seven Hundred Twenty Thousand Seven Hundred Fifty-Three 80 1721120 0001-03-03 B.C. 1720754 One Million Seven Hundred Twenty Thousand Seven Hundred Fifty-Four ... snip 1721120-1721420 no major change there... 381 1721421 0001-12-29 B.C. 1721055 One Million Seven Hundred Twenty-One Thousand Fifty-Five 382 1721422 0001-12-30 B.C. 1721056 One Million Seven Hundred Twenty-One Thousand Fifty-Six 383 1721423 0001-12-31 B.C. 1721057 One Million Seven Hundred Twenty-One Thousand Fifty-Seven <span style="color:blue;">384 1721424 0001-01-01 A.D. 1721424 One Million Seven Hundred Twenty-One Thousand Four Hundred Twenty-Four</span> 385 1721425 0001-01-02 A.D. 1721425 One Million Seven Hundred Twenty-One Thousand Four Hundred Twenty-Five 386 1721426 0001-01-03 A.D. 1721426 One Million Seven Hundred Twenty-One Thousand Four Hundred Twenty-Six 387 1721427 0001-01-04 A.D. 1721427 One Million Seven Hundred Twenty-One Thousand Four Hundred Twenty-Seven 388 1721428 0001-01-05 A.D. 1721428 One Million Seven Hundred Twenty-One Thousand Four Hundred Twenty-Eight 389 1721429 0001-01-06 A.D. 1721429 One Million Seven Hundred Twenty-One Thousand Four Hundred Twenty-Nine 390 1721430 0001-01-07 A.D. 1721430 One Million Seven Hundred Twenty-One Thousand Four Hundred Thirty 391 1721431 0001-01-08 A.D. 1721431 One Million Seven Hundred Twenty-One Thousand Four Hundred Thirty-One 392 1721432 0001-01-09 A.D. 1721432 One Million Seven Hundred Twenty-One Thousand Four Hundred Thirty-Two 393 1721433 0001-01-10 A.D. 1721433 One Million Seven Hundred Twenty-One Thousand Four Hundred Thirty-Three 394 1721434 0001-01-11 A.D. 1721434 One Million Seven Hundred Twenty-One Thousand Four Hundred Thirty-Four 395 1721435 0001-01-12 A.D. 1721435 One Million Seven Hundred Twenty-One Thousand Four Hundred Thirty-Five 396 1721436 0001-01-13 A.D. 1721436 One Million Seven Hundred Twenty-One Thousand Four Hundred Thirty-Six 397 1721437 0001-01-14 A.D. 1721437 One Million Seven Hundred Twenty-One Thousand Four Hundred Thirty-Seven 398 1721438 0001-01-15 A.D. 1721438 One Million Seven Hundred Twenty-One Thousand Four Hundred Thirty-Eight 399 1721439 0001-01-16 A.D. 1721439 One Million Seven Hundred Twenty-One Thousand Four Hundred Thirty-Nine 400 1721440 0001-01-17 A.D. 1721440 One Million Seven Hundred Twenty-One Thousand Four Hundred Forty</pre> <p>Two strange things to observe. If we look closely we can see that the <strong>year 1 BC repeats</strong> itself two times. For example line 17 and line 383 both show the 31st of December 1 BC. I now say 1 BC[1] and 1 BC[2] to distinguish the entries for those years. Second observation is that the <strong>29th of February 1 BC[2] exists</strong> and is kind of <strong>undefined</strong> (0000-00-00 0000 0000000). The 29th of februar in year 1 BC[1] does not exist in the data. This is not shown in the sample set, but you can easily modify the query to see for yourself.</p> <p>In older DB versions the second 1 BC occurence would be year 0. For which some of the date functions also return the error message </p> <pre style="color:red;">ORA-01841: (full) year must be between -4713 and +9999, <strong>and not be 0</strong></pre> <p>I believe that there was some half baked bug fix at oracle. Year 0 was aliased as Year 1 BC. This also explains, why there seems to be a leap day. Year 0 would have a leap day according to the logical rules (as defined by Pope Gregory XIII). In older database versions any day from the year 0 resulted in 0000-00-00 0000. Which also created problems. Fortunatly the issue only seems to appear when playing around with the J(ulian) format. And even then only for some very large values. The chance to get bugs in real world systems is extremly slim.</p> <p><strong>some more examples</strong><br /> <em>Date based comparison<br /> </em></p> <pre class="brush: sql; light: true; title: ; notranslate">select case when 1721057 = 1721423 then 'equal' else 'unequal' end as "check" from dual;</pre> <pre style="color:green;">unequal</pre> <p>As expected those two numbers are not equal.<br /> Compare the same numbers, but added to the same date.</p> <pre class="brush: sql; light: true; title: ; notranslate">select case when to_date('01-01-4712 BC','DD-MM-YYYY AD') + 1721057 = to_date('01-01-4712 BC','DD-MM-YYYY AD') + 1721423 then 'equal' else 'unequal' end as "check" from dual;</pre> <pre style="color:red;">equal</pre> <p>Now they are equal.</p> <p><em>consecutive day check</em></p> <p>Negative years within a date literal are BC years. Here follows a shot list of small date calculations around the problematic years and days.</p> <pre class="brush: sql; light: true; title: ; notranslate">select to_char(date '-0001-12-31','DD-Mon-YYYY AD') from dual;</pre> <pre>31-Dec-0001 BC</pre> <pre class="brush: sql; light: true; title: ; notranslate">select to_char(date '-0001-12-31' + 1,'DD-Mon-YYYY AD') from dual;</pre> <pre>01-Jan-0001 AD</pre> <p>31-Dec-0001 BC + 1 = 01-Jan-0001 AD</p> <pre class="brush: sql; light: true; title: ; notranslate">select to_char(date '-0001-01-01' - 1,'DD-Mon-YYYY AD') from dual;</pre> <pre>31-Dec-0002 BC</pre> <p>01-Jan-0001 BC &#8211; 1 = 31-Dec-0002 BC</p> <pre class="brush: sql; light: true; title: ; notranslate">select to_char(date '-0002-12-31' + 1,'DD-Mon-YYYY AD') from dual;</pre> <pre>01-Jan-0001 BC</pre> <p>31-Dec-0002 BC + 1 = 01-Jan-0001 BC</p> <pre class="brush: sql; light: true; title: ; notranslate">select to_char(date '-0001-02-28' + 1,'DD-Mon-YYYY AD') from dual;</pre> <pre>01-Mar-0001 BC</pre> <p>28-Feb-0001 BC = 01-Mar-0001 BC</p> <p>Seems about right.</p> <p>At least here Oracle adhers to ISO 8601 regulation &#8220;every date must be consecutive&#8221;.</p> <p>And some more edge cases</p> <pre class="brush: sql; light: true; title: ; notranslate">select to_char(date '-4712-1-1','YYYY A.D.') from dual;</pre> <pre>4712 B.C.</pre> <pre class="brush: sql; light: true; title: ; notranslate">select to_char(date '-1000000','YYYY A.D.') from dual;</pre> <pre style="color:red;">ORA-01841: (full) year must be between -4713 and +9999, and not be 0</pre> <p>So there is no 1 Million Years B.C. in the Oracle DB.</p> <h2>4) The first ISO-year day for 1st Januar 2021 is in 2019</h2> <pre class="brush: sql; light: true; title: ; notranslate">select to_char(trunc(date '2021-01-01','IYYY'),'YYYY-MM-DD') from dual; 2019-12-30 </pre> <p>Now this looks strange! It happens in all supported DB versions.<br /> According to the <a href="https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sqlrf/ROUND-and-TRUNC-Date-Functions.html#GUID-8E10AB76-21DA-490F-A389-023B648DDEF8" target="_blank" rel="noopener">docs</a> IYYY is a supported format model for TRUNC. It is specified as &#8220;Year containing the calendar week, as defined by the <a href="https://en.wikipedia.org/wiki/ISO_8601" target="_blank">ISO 8601 standard</a>&#8220;.<br /> Note that the doc mentions the calendar week. The 1st Januar 2021 is in calendar week (IW) 53. That week still is part of year 2020. And the first day (Monday) of the first ISO week of 2020 is 30th of December 2019.</p> <p>So it seems as if</p> <pre class="brush: sql; light: true; title: ; notranslate">TRUNC(:date,'IYYY') </pre> <p>really does:</p> <pre class="brush: sql; light: true; title: ; notranslate"> TRUNC( TRUNC( TRUNC(:date,'IW') -- first day of the iso-week ,'YEAR') -- first day of the calendar YEAR regardless of iso ,'IW') -- first day of iso-week </pre> <p>I think this is illogical behaviour and as such should be considered a bug. However it is correct in terms of the ISO 8601 &#8211; which calls it the &#8220;ISO week-numbering year&#8221;. So most likely it will not be fixed.</p> <p>Remember: Always truncate useing &#8216;YEAR&#8217; or &#8216;YYYY&#8217;, <strong>never use &#8216;IYYY&#8217;</strong> it is just to confusing.</p> <h2>5) lateral SQL injection</h2> <p>Consider the following code. Is it safe?</p> <pre class="brush: sql; title: ; notranslate"> create or replace procedure date_proc(p_date in date) is stmt varchar2(200); res varchar2(100); begin stmt:='select object_name from all_objects where created = ''' || p_date ||''''; dbms_output.enable; dbms_output.put_line(stmt); execute immediate stmt into res; dbms_output.put_line('result:'||res); exception when no_data_found then dbms_output.put_line('result: no objects found'); end; / set serveroutput on execute date_proc(sysdate); </pre> <p>Dynamic sql is always at risk for sql injection. However since that code makes sure the value is a correct date it doesn&#8217;t seem possible to tamper with the code.</p> <p>This is just some demo code. It has other issues as well (like removing time from the input).</p> <p>Afaik David Litchfield was the first to describe the potential security issue with this. He called it the Lateral SQL injection. I prefer the name SQL injection by NLS.</p> <p>See also: <a href="http://www.hexatier.com/lateral-sql-injection-in-oracle-database/" rel="nofollow">http://www.hexatier.com/lateral-sql-injection-in-oracle-database/</a></p> <p>Consider the following NLS setting. Any client can modify its NLS environment.</p> <pre class="brush: sql; title: ; notranslate">alter session set nls_date_format = 'DD/MM/YYYY"'' or 1=1"--'; </pre> <p>Then run the statement again!</p> <pre class="brush: sql; title: ; notranslate"> set serveroutput on execute date_proc(sysdate); </pre> <pre>select object_name from all_objects where created = '16/07/2018 ' or 1=1--' <span style="color:red;">ORA-01422: exact fetch returns more than requested number of rows</span> </pre> <p>Ok this happens, because the code doesn&#8217;t expect multiple rows to be returned. We can modify that.</p> <pre class="brush: sql; title: ; notranslate"> alter session set nls_date_format = 'DD/MM/YYYY"'' or 1=1 and rownum=1"--'; </pre> <p>Fortunatly the possibilites via NLS format are limited. For example the length of the injected code can only be very small. When trying more complex modifications we get</p> <pre style="color:red;">ORA-01801: date format is too long for internal buffer</pre> <p>However sometimes this can potentially be used as a first step for more serious hacking.</p> <p>A similar exploit is possible using the NUMBER datatype (via nls_numeric_characters).</p> <p>The more interesting question is, how to correct code like this.<br /> One option is to use bind variables.</p> <pre class="brush: sql; highlight: [5,8]; title: ; notranslate"> create or replace procedure date_proc(p_date in date) is stmt varchar2(200); res varchar2(100); begin stmt:='select object_name from all_objects where created = :dat'; dbms_output.enable; dbms_output.put_line(stmt); execute immediate stmt into res using p_date ; dbms_output.put_line('result:'||res); exception when no_data_found then dbms_output.put_line('result: no objects found'); end; / </pre> <p>Other options include validating any concatenated input for example by using dbms_assert.</p> <h1>Conclusion</h1> <p>Calendars are difficult. Oracle implemented calendar functionality very thoroughly.<br /> It is the duty of a developer/DBA to understand the complexities around calendars, time zones, time conversions and Time Machines. </p> <p>If you found any movie references &#8211; keep them!</p> svenweller http://svenweller.wordpress.com/?p=7769 Tue Jul 17 2018 13:32:24 GMT-0400 (EDT) Copy and Paste to clipboard https://www.apex-at-work.com/2018/07/copy-and-paste-to-clipboard.html Well I had the requirement to copy the content of a textarea into the clipboard. There are two ways to do that:<br /><br />1. Build a dynamic action with custom Javascript code:<br /><a href="https://www.w3schools.com/howto/howto_js_copy_clipboard.asp">Copy Text to Clipboard</a> <br /><br /><span style="font-family: inherit;">Code example - with dynamic action on "Click" and "Execute Javascript Code":</span><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">/* Select the text field */<br />$('#P1_APEX_ITEM').select();<br /><br />/* Copy the text inside the text field */<br />document.execCommand("copy");</span><br /><br /><br />2. Use an APEX plugin:<br /><a href="https://apex.world/ords/f?p=100:710:4357238555384::::P710_PLG_ID:NL.DETORA.APEX.COPY_TO_CLIPBOARD">Copy to Clipboard (v1.1)</a> - build by Dick Dral<br /><br /><br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-6VrlLdrEL74/W024_86dVvI/AAAAAAAAB-Y/58Bwba1bmMUm-QPGWtE6aL-9lBd1DkbLgCLcBGAs/s1600/copy.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="256" data-original-width="256" height="200" src="https://1.bp.blogspot.com/-6VrlLdrEL74/W024_86dVvI/AAAAAAAAB-Y/58Bwba1bmMUm-QPGWtE6aL-9lBd1DkbLgCLcBGAs/s200/copy.png" width="200" /></a></div><span style="font-size: xx-small;">Icons made by <a href="https://www.flaticon.com/authors/vitaly-gorbachev" title="Vitaly Gorbachev">Vitaly Gorbachev</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> is licensed by <a href="http://creativecommons.org/licenses/by/3.0/" target="_blank" title="Creative Commons BY 3.0">CC 3.0 BY</a></span> Tobias Arnhold tag:blogger.com,1999:blog-6481483192141562388.post-58224673597607349 Tue Jul 17 2018 05:33:00 GMT-0400 (EDT) Creating a CRUD form on a REST Service with APEX 18.1 https://blogs.oracle.com/apex/creating-a-crud-form-on-a-rest-service-with-apex-181 <p>In this blog posting we will highlight the new REST capabilities of Application Express 18.1 once more. This time we will show how to create a form to insert, update or delete rows - but not from a table, the form will work on a REST service instead.</p> <p>APEX 18.1 provides declarative support to build components on top of a REST service. However, only&nbsp;<em>Read Only</em>&nbsp;components like like reports or charts can use Web Source Modules directly; there is no wizard to create a form on a Web Source Module.</p> <p>So we have to implement some custom PL/SQL code in order to build a DML form on a REST service. As this blog posting shows, Web Source Modules can still do a lot of the work for us: <em>We will still be able to use the <strong>APEX_EXEC</strong> package - no manual JSON parsing will be required and we won&#39;t have to do any manual HTTP request.</em></p> <p>Note that full declarative support for Read/Write components like Forms or the Interactive Grid is planned for one of the next releases of Application Express - when that is available, you will be able to create a Form on a REST service directly, without any manual work at all - as you can do today with a report.</p> Provide a REST Service: Using ORDS Auto-REST <p>First we need the REST Service to work on. For this blog posting we will use the well-known EMP table and the <a href="https://docs.oracle.com/database/ords-18.1/AELIG/developing-REST-applications.htm#AELIG90103" target="_blank">&quot;Auto-REST&quot; feature of Oracle REST Data Services</a>. The most easy approach is to navigate to SQL Workshop &gt; SQL Commands and to execute the following simple PL/SQL Block:</p> begin ords.enable_schema; ords.enable_object( p_object =&gt; &#39;EMP&#39; ); end; / <p>Then, to check whether the REST Service works, try to execute the REST Service using a browser or the &quot;curl&quot; command line utility. Use the URL: <strong>http://{ords-server}:{port}/ords/{schema}/emp/.&nbsp;</strong>&nbsp;With a browser, the response should look as follows:</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/1d3ffe47b352ea657c7d0b8baf700bb0/bildschirmfoto_2018_07_16_um_10_15_31.png" style="width: 1932px; height: 1170px;" /></p> Create the APEX Web Source Module <p>Then, head over to Application Express, log into your workspace and create an application. Navigate to <strong>Shared Components</strong> and lookup <strong>Web Source Modules</strong>. In a new application, this section is empty. Click the&nbsp;<strong>Create</strong>&nbsp;button in order to create a new Web Source Module <strong>from Scratch</strong>.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/53c9046001d4ae589ac610e1dd114dfb/bildschirmfoto_2018_07_16_um_10_17_15.png" style="width: 2600px; height: 844px;" /></p> <p>Choose <strong>Oracle REST Data Services</strong> as the <strong>Web Source Type</strong>, provide the <strong>URL endpoint</strong> and click <strong>Next</strong>.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/07445b157b4f33ab41578ae277f45eca/bildschirmfoto_2018_07_16_um_10_17_41.png" style="width: 1648px; height: 986px;" /></p> <p>Just click the <strong>Next</strong> button in the following wizard step for the <strong>Remote Server</strong>. In the <strong>Authentication</strong> step, simply hit the <strong>Discover</strong> button. You should see the following screen, which indicates that APEX can talk to the REST service.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/1ec46e498c05f6480ca9a01874f4b07f/bildschirmfoto_2018_07_16_um_10_17_54.png" style="width: 1598px; height: 958px;" />Click&nbsp;<strong>Create Web Source Module</strong>&nbsp;in order to save REST service meta data. You will be navigated back to the list of web source modules.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/0b47645e3040da9ae626730b46638a0d/bildschirmfoto_2018_07_16_um_10_23_23.png" style="width: 2160px; height: 662px;" /></p> Create a report on top of the Web Source Module <p>Then create a classic report on that Web Source module, as described in the<span>&nbsp;<a href="https://blogs.oracle.com/apex/get-started-with-rest-services-in-application-express-52-ea-1">Application Express Early Adopter: REST Services!</a> </span>blog posting. You can also use page designer: Drag a classic report region onto your page and change the&nbsp;<strong>Source</strong>&nbsp;attributes in the property pane on the right to use the new Web Source Module.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/e060fcd4a0015d14ce2ea7b2d0e21d48/bildschirmfoto_2018_07_16_um_10_18_53.png" style="width: 2988px; height: 1332px;" />Run the page. You should see the data from the EMP table - which actually comes from a REST service.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/ad996b9b3fc3428639cef4891b87a0da/bildschirmfoto_2018_07_16_um_10_19_12.png" style="width: 1788px; height: 1654px;" /></p> <p>This was the read only part. Now we&#39;ll get to the read / write part of the story.&nbsp;</p> Insert, Update or Delete on a REST Service <p>When we REST-Enabled the EMP table (with <strong>ORDS.ENABLE_OBJECT</strong>), not only a GET REST Service had been created. ORDS also provides REST Services to perform DML (insert, update or delete) rows.</p> <ul> <li><strong>INSERT</strong>:<br /> POST Request to <strong>http://{server}:{port}/ords/{schema}/emp/</strong>.<br /> The request body contains the data for the new row in JSON format.</li> <li><strong>UPDATE</strong>:<br /> PUT Request to <strong>http://{server}:{port}/ords/{schema}/emp/{empno}</strong>.<br /> The request body contains the data for the new row in JSON format.</li> <li><strong>DELETE</strong>:<br /> DELETE Request to <strong>http://{server}:{port}/ords/{schema}/emp/{empno}</strong>.<br /> The request body must be empty.</li> </ul> <p>Let&#39;s first try that with the &quot;curl&quot; command line utility (which is always a good tool to test our understanding of a REST service). The following <strong>curl</strong> invocation creates a new row by executing a POST request.</p> curl -H&quot;Content-Type:application/json&quot; \ -X POST \ -d&#39;{&quot;empno&quot;:4711,&quot;ename&quot;:&quot;APEX&quot;,&quot;job&quot;:&quot;DEV&quot;,&quot;hiredate&quot;:&quot;2001-01-01T20:00:00Z&quot;,&quot;sal&quot;:10,&quot;comm&quot;:null,&quot;deptno&quot;:10,&quot;mgr&quot;:7839}&#39; \ http://localhost:28080/ords/testit/emp/ <p>You should see the following resonse, indicating that the operation was successful.</p> {&quot;empno&quot;:4711,&quot;ename&quot;:&quot;APEX&quot;,&quot;job&quot;:&quot;DEV&quot;,&quot;mgr&quot;:7839,&quot;hiredate&quot;:&quot;2001-01-01T20:00:00Z&quot;,&quot;sal&quot;:10,&quot;comm&quot;:null,&quot;deptno&quot;:10,&quot;links&quot;:[{&quot;rel&quot;:&quot;self&quot;,&quot;href&quot;:&quot;http://localhost:28080/ords/testit/emp/4711&quot;},{&quot;rel&quot;:&quot;edit&quot;,&quot;href&quot;:&quot;http://localhost:28080/ords/testit/emp/4711&quot;},{&quot;rel&quot;:&quot;describedby&quot;,&quot;href&quot;:&quot;http://localhost:28080/ords/testit/metadata-catalog/emp/item&quot;},{&quot;rel&quot;:&quot;collection&quot;,&quot;href&quot;:&quot;http://localhost:28080/ords/testit/emp/&quot;}]} <p>We can also check by querying the table directly:</p> SQL&gt; select * from emp; EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO ------- -------- ------------- ---- ---------------------- ----- ------ -------- 7369 SMITH CLERK 7902 17.12.1980 00:00:00 800 20 7499 ALLEN SALESMAN 7698 20.02.1981 00:00:00 1600 300 30 7521 WARD SALESMAN 7698 22.02.1981 00:00:00 1250 500 30 7566 JONES MANAGER 7839 02.04.1981 00:00:00 2975 20 7654 MARTIN SALESMAN 7698 28.09.1981 00:00:00 1250 1400 30 7698 BLAKE MANAGER 7839 01.05.1981 00:00:00 2850 30 7782 CLARK MANAGER 7839 09.06.1981 00:00:00 2450 10 7788 SCOTT ANALYST 7566 09.12.1982 00:00:00 3000 20 7839 KING PRESIDENT 17.11.1981 00:00:00 5000 10 7844 TURNER SALESMAN 7698 08.09.1981 00:00:00 1500 0 30 7876 ADAMS CLERK 7788 12.01.1983 00:00:00 1100 20 7900 JAMES CLERK 7698 03.12.1981 00:00:00 950 30 7902 FORD ANALYST 7566 03.12.1981 00:00:00 3000 20 7934 MILLER CLERK 7782 23.01.1982 00:00:00 1300 10 <b> 4711 APEX DEV 7839 01.01.2001 12:00:00 10 10 </b> <p>Since we now know, how to call the POST, PUT and DELETE REST Services, let&#39;s prepare the already existing Web Source Module and then build the CRUD form.</p> Prepare the Web Source Module for CRUD operations <p>Since APEX 18.1 does not provide declarative support for Forms on a Web Source Module, we must provide some information ourselves, but we can still leverage Web Source Modules and let APEX do a lot of low-level work for us.</p> <p>Look up your new web source module in <strong>Shared Components</strong>. First, navigate to the <strong>Advanced</strong> tab and note down the exact <strong>Static ID </strong>value of the Web Source Module (here:&nbsp;<strong>Auto_REST_Service_EMP</strong>).&nbsp;We&#39;ll need that later on.<img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/584b104cb4f8eb5bbcb85f5474200896/bildschirmfoto_2018_07_16_um_11_00_12.png" style="width: 2354px; height: 794px;" />​</p> <p>&nbsp;</p> <p>&nbsp;</p> <p>Then select the <strong>Operations</strong> tab.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/b1dffe8c88794769c016be997f82988b/bildschirmfoto_2018_07_16_um_10_41_12.png" style="width: 2738px; height: 1130px;" /></p> <p>We can see that APEX already did some work for us. Since this is an ORDS REST Service, APEX detected, that URL endpoints for POST, PUT and DELETE exist and it added these to the REST Service meta data.</p> Remove the unneeded DELETE operation <p>ORDS provides indeed two DELETE endpoints: One is to delete a single row, the other one to delete the whole collection (i.e. all rows from the table). We won&#39;t need the latter one in our APEX application. So click the yellow pencil of the DELETE operation which has <em>no value</em> in the <strong>Database Operation</strong> column and remove that operation by clicking the <strong>Delete</strong> button.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/77b4a02540536b56c1a85939c3e14d4f/bildschirmfoto_2018_07_16_um_10_41_12.png" style="width: 2738px; height: 1130px;" /></p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/d1ee3d850ec3804177fb9e3b0068e784/bildschirmfoto_2018_07_16_um_11_47_42.png" style="width: 2344px; height: 926px;" /></p> Changes to the POST operation <p>Then, click the pencil to edit the <strong>POST</strong> operation.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/cd8bd63d28d22248f96c01d1177a9b70/bildschirmfoto_2018_07_16_um_10_42_37.png" style="width: 2342px; height: 1290px;" />Provide the following JSON template as the <strong>Request Body Template</strong>.</p> {&quot;empno&quot;:#EMPNO#,&quot;ename&quot;:&quot;#ENAME#&quot;,&quot;job&quot;:&quot;#JOB#&quot;,&quot;hiredate&quot;:&quot;#HIREDATE#&quot;,&quot;sal&quot;:#SAL#,&quot;comm&quot;:#COMM#,&quot;deptno&quot;:#DEPTNO#,&quot;mgr&quot;:#MGR#} <p>Click Apply Changes and then the pencil again to come back to this form. Then click the <strong>Add Parameter</strong> button to open the Operation Parameter dialog.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/7c6cb79b286f868932e61b2484aeeed4/bildschirmfoto_2018_07_16_um_10_47_08.png" style="width: 2348px; height: 1048px;" /></p> <p>For each column name, which you have created a<strong> #PLACEHOLDER#</strong> for, add a Parameter of the <strong>Request / Response Body</strong> type.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/bf76a81c26220d84850b7e8c1d9dcab9/bildschirmfoto_2018_07_16_um_10_48_31.png" style="width: 2154px; height: 1046px;" />When finished, you should have eight Operation Parameters, one for each column of the EMP table. Then add another parameter of Type <strong>HTTP Header </strong>with<strong>&nbsp;</strong><strong>Content-Type</strong>&nbsp;as its name and <strong>application/json</strong>&nbsp;as the value. The <strong>Operation Parameters</strong> section for the POST operation should finally look as follows.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/afb3f50536bddaa951d954da7449ac64/bildschirmfoto_2018_07_16_um_10_51_00.png" /></p> Changes to the PUT operation. <p>For the PUT operation, provide the following <strong>JSON Request Body template</strong> (it&#39;s similar to the template for the POST operation, but without the EMPNO column).</p> {&quot;ename&quot;:&quot;#ENAME#&quot;,&quot;job&quot;:&quot;#JOB#&quot;,&quot;hiredate&quot;:&quot;#HIREDATE#&quot;,&quot;sal&quot;:#SAL#,&quot;comm&quot;:#COMM#,&quot;deptno&quot;:#DEPTNO#,&quot;mgr&quot;:#MGR#} <p>Then add Web Source Parameters as well, similar as done for the POST operations:</p> <ul> <li>One Parameter of type <strong>Request / Response body</strong> for each <strong>#PLACEHOLDER#</strong> in the JSON Request Template</li> <li>One static Parameter of type <strong>HTTP Header</strong> with <strong>Content-Type</strong> as the <strong>Name</strong> and <strong>application/json</strong> as the <strong>value</strong></li> <li>One Parameter of type&nbsp;<strong>URL Pattern variable</strong><span style="white-space:pre"> with name <strong>id</strong>.</span></li> </ul> <p><span style="white-space:pre">The Operation parameters section for the PUT operation should look as follows:</span></p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/82198165204ef4f6eb1ccb66db661090/bildschirmfoto_2018_07_16_um_12_06_16.png" style="width: 2532px; height: 1254px;" /></p> Changes to the DELETE operation <p>The remaining DELETE operation does not need any JSON Request template and only one parameter definition: Create a parameter of type <strong>URL pattern variable</strong> with name <strong>id</strong>.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/7c9ec7a7c45e18344bf98e716f54772b/bildschirmfoto_2018_07_16_um_12_01_56.png" style="width: 2552px; height: 828px;" /></p> <p>Now, the operations are all set and the Web Source Module has been prepared. We can continue building the form page.</p> Create the form page <p>Next, create a new page for the form on the REST service. Create a blank page and add a region containing eight items (one for each form element) to that page. When finished, your form might looks as follows (it has no functionality so far).</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/37181407e11560db90341c52b850c207/bildschirmfoto_2018_07_16_um_10_57_04.png" style="width: 2340px; height: 1100px;" />Next, we&#39;ll add functionality to populate the form with values on page load. We&#39;ll need do this using custom PL/SQL code and the <a href="https://docs.oracle.com/database/apex-18.1/AEAPI/APEX_EXEC.htm#AEAPI-GUID-3CF1D2DD-AEA4-4982-9857-548567AB7169" target="_blank"><strong>APEX_EXEC</strong></a> package. The blog posting&nbsp;<span> <a href="https://blogs.oracle.com/apex/apex-181-early-adopter-2-rest-services-and-plsql">APEX 18.1 Early Adopter 2: REST Services and PL/SQL</a> </span>contains a good template for our form loading process.&nbsp;</p> <p>In Page Designer, navigate to the Before Headers section in the page tree on the left and create a new Process.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/e5dff30292d767e8d97b0de6b50a6742/bildschirmfoto_2018_07_16_um_11_13_07.png" /></p> <p>Name the process <strong>Load REST Data</strong> and provide the following PL/SQL Code:</p> declare l_columns apex_exec.t_columns; l_context apex_exec.t_context; l_filters apex_exec.t_filters; type t_column_position is table of pls_integer index by varchar2(32767); l_column_position t_column_position; begin -- specify columns to select from the web source module apex_exec.add_column( p_columns =&gt; l_columns, p_column_name =&gt; &#39;EMPNO&#39;); apex_exec.add_column( p_columns =&gt; l_columns, p_column_name =&gt; &#39;ENAME&#39;); apex_exec.add_column( p_columns =&gt; l_columns, p_column_name =&gt; &#39;JOB&#39;); apex_exec.add_column( p_columns =&gt; l_columns, p_column_name =&gt; &#39;HIREDATE&#39;); apex_exec.add_column( p_columns =&gt; l_columns, p_column_name =&gt; &#39;MGR&#39;); apex_exec.add_column( p_columns =&gt; l_columns, p_column_name =&gt; &#39;SAL&#39;); apex_exec.add_column( p_columns =&gt; l_columns, p_column_name =&gt; &#39;COMM&#39;); apex_exec.add_column( p_columns =&gt; l_columns, p_column_name =&gt; &#39;DEPTNO&#39;); -- add a filter to query only the selected row apex_exec.add_filter( p_filters =&gt; l_filters, p_column_name =&gt; &#39;EMPNO&#39;, p_filter_type =&gt; apex_exec.c_filter_eq, p_value =&gt; to_number( :P2_EMPNO ) ); -- invoke Web Source Module and select data l_context := apex_exec.open_web_source_query( p_module_static_id =&gt; &#39;Auto_REST_Service_EMP&#39;, p_filters =&gt; l_filters, p_columns =&gt; l_columns ); -- now get result set positions for the selected columns for c in 1 .. l_columns.count loop l_column_position( l_columns( c ).name ) := apex_exec.get_column_position( l_context, l_columns( c ).name ); end loop; -- if we have a result set, set the form items if apex_exec.next_row( l_context ) then :P2_ENAME := apex_exec.get_varchar2( l_context, l_column_position( &#39;ENAME&#39; ) ); :P2_JOB := apex_exec.get_varchar2( l_context, l_column_position( &#39;JOB&#39; ) ); :P2_HIREDATE := apex_exec.get_varchar2( l_context, l_column_position( &#39;HIREDATE&#39; ) ); :P2_SAL := apex_exec.get_number ( l_context, l_column_position( &#39;SAL&#39; ) ); :P2_COMM := apex_exec.get_number ( l_context, l_column_position( &#39;COMM&#39; ) ); :P2_MGR := apex_exec.get_number ( l_context, l_column_position( &#39;MGR&#39; ) ); :P2_DEPTNO := apex_exec.get_number ( l_context, l_column_position( &#39;DEPTNO&#39; ) ); -- otherwise raise NO_DATA_FOUND else raise no_data_found; end if; -- finally: release all resources apex_exec.close( l_context ); exception when others then -- IMPORTANT: also release all resources, when an exception occcurs! apex_exec.close( l_context ); raise; end; <p>Add a server-side condition to have the process only executed when the <strong>P2_EMPNO</strong> item<strong> IS NOT NULL</strong>, then&nbsp;save your changes.</p> <p>Let&#39;s now test whether this PL/SQL code already works. Navigate back to the report page and change the <strong>EMPNO</strong> column of the report to be rendered as a link to the new form page.&nbsp;</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/1f76048a45f98f1d76b74821d76d1910/bildschirmfoto_2018_07_16_um_11_15_44.png" style="width: 2760px; height: 1542px;" /></p> <p>Run the report page - you should now see links in the <strong>EMPNO</strong> column.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/aff0b19f883b9aef3a4c2063fa2f2752/bildschirmfoto_2018_07_16_um_11_17_06.png" style="width: 1238px; height: 1158px;" /></p> <p>Then add a button to the report page which allows to create a new row.</p> <ul> <li><strong>Button Name</strong>: CREATE_NEW</li> <li><strong>Button Label</strong>: Create New</li> <li><strong>Button Action</strong>: Redirect to Page</li> <li><strong>Target</strong>: Page 2 (the form page); set <strong>Clear Cache</strong> for page 2 (the form page)</li> </ul> <p>When clicking the link in the <strong>EMPNO</strong> column, the form page should be loaded and populated with the values for the selected row; when clicking the <strong>Create New</strong> button, an empty form should be loaded.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/e9503fa4afeab015db84e7580f1c70be/bildschirmfoto_2018_07_16_um_11_17_14.png" style="width: 2326px; height: 976px;" />This&nbsp;concludes the first part of the form page. We loaded data from the REST service into the page items without using any <strong>APEX_WEB_SERVICE</strong> call and without doing any manual JSON parsing.</p> Add DML processes to the form <p>Before adding the PL/SQL code to process POST, PUT and DELETE requests add the required buttons to the page:</p> <ul> <li><strong>CREATE</strong> with an&nbsp;<strong>IS NULL</strong> condition for the&nbsp;<strong>P2_ENAME&nbsp;</strong>item</li> <li><strong>APPLY_CHANGES</strong> with the<strong>&nbsp;IS NOT NULL</strong> condition for the&nbsp;<strong>P2_ENAME </strong>item</li> <li><strong>DELETE&nbsp;</strong>with the<strong>&nbsp;IS NOT NULL</strong>&nbsp;condition for the&nbsp;<strong>P2_ENAME&nbsp;</strong>item</li> </ul> <p>The page should then look as follows:</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/6d8e9e1a1aea2d680aa06973b1b1e373/bildschirmfoto_2018_07_16_um_11_22_05.png" style="width: 2356px; height: 1086px;" /></p> <p>Now let&#39;s add the PL/SQL Code to process the INSERT, UPDATE or DELETE operations. We have provided all required meta data in the Web Source Modules and we can thus work with the APEX_EXEC package alone. Dependent on the button clicked, the PL/SQL code will prepare parameters for the Web Source Module operation and finally call <a href="https://docs.oracle.com/database/apex-18.1/AEAPI/EXECUTE_WEB_SOURCE-Procedure.htm#AEAPI-GUID-30272C98-EA7B-4220-A26B-63DFF9DFCD1F" target="_blank">APEX_EXEC.PROCESS_WEB_SOURCE</a>.&nbsp;</p> <p>In Page Designer, create a new PL/SQL process in the Processing section.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/3c9574bd82c2cc360a4c3d6860f95491/bildschirmfoto_2018_07_16_um_12_14_51.png" style="width: 1958px; height: 1188px;" /></p> <p>Name it <strong>Process REST DML</strong> and provide the following PL/SQL code:</p> declare l_parameters apex_exec.t_parameters; begin -- add the primary key value as the &quot;id&quot; parameter; this will be appended to the URL for DELETE and APPLY_CHANGES if :REQUEST in ( &#39;DELETE&#39;, &#39;APPLY_CHANGES&#39; ) then apex_exec.add_parameter( p_parameters =&gt; l_parameters, p_name =&gt; &#39;id&#39;, p_value =&gt; :P2_EMPNO ); end if; -- add form item values as parameters for CREATE and APPLY_CHANGES if :REQUEST in ( &#39;CREATE&#39;, &#39;APPLY_CHANGES&#39; ) then apex_exec.add_parameter( p_parameters =&gt; l_parameters, p_name =&gt; &#39;ENAME&#39;, p_value =&gt; :P2_ENAME ); apex_exec.add_parameter( p_parameters =&gt; l_parameters, p_name =&gt; &#39;EMPNO&#39;, p_value =&gt; :P2_EMPNO ); apex_exec.add_parameter( p_parameters =&gt; l_parameters, p_name =&gt; &#39;JOB&#39;, p_value =&gt; :P2_JOB ); apex_exec.add_parameter( p_parameters =&gt; l_parameters, p_name =&gt; &#39;HIREDATE&#39;, p_value =&gt; to_char( to_date( :P2_HIREDATE ), &#39;YYYY-MM-DD&#39; ) || &#39;T00:00:00Z&#39; ); apex_exec.add_parameter( p_parameters =&gt; l_parameters, p_name =&gt; &#39;SAL&#39;, p_value =&gt; :P2_SAL ); apex_exec.add_parameter( p_parameters =&gt; l_parameters, p_name =&gt; &#39;COMM&#39;, p_value =&gt; coalesce( :P2_COMM, &#39;null&#39; ) ); apex_exec.add_parameter( p_parameters =&gt; l_parameters, p_name =&gt; &#39;MGR&#39;, p_value =&gt; :P2_MGR ); apex_exec.add_parameter( p_parameters =&gt; l_parameters, p_name =&gt; &#39;DEPTNO&#39;, p_value =&gt; :P2_DEPTNO ); end if; -- invoke Web Source Module for and select data apex_exec.execute_web_source( p_module_static_id =&gt; &#39;Auto_REST_Service_EMP&#39;, p_operation =&gt; case :REQUEST when &#39;APPLY_CHANGES&#39; then &#39;PUT&#39; when &#39;CREATE&#39; then &#39;POST&#39; when &#39;DELETE&#39; then &#39;DELETE&#39; end, p_parameters =&gt; l_parameters ); end; <p>As <strong>Server-Side condition</strong>, choose <strong>Request is contained in value</strong> and provide&nbsp;<strong>CREATE:APPLY_CHANGES:DELETE</strong> as the Value. That makes sure that the code is only called when one of the three buttons has been clicked. Finally provide a nice success message and add a branch back to the report page (here: page 1).</p> <p>Now we can test the CRUD form:</p> <ul> <li>Click the <strong>Create New</strong> button below the report, enter some data and save a new row<br /> <img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/42ba92c51e8c68a58c53b959133120b2/bildschirmfoto_2018_07_16_um_12_44_52.png" style="width: 2536px; height: 1042px;" /><br /> <img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/5ce05ddfa281f3526332d39368dd1cb4/bildschirmfoto_2018_07_16_um_12_45_07.png" /></li> <li>Update the <strong>Name</strong> value of that new row<br /> <img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/055805d3ad0ead173c650984efc2bca2/bildschirmfoto_2018_07_16_um_12_45_21.png" style="width: 2508px; height: 712px;" /></li> </ul> <p>Of course, this form can be further extended - think about validations, additional processes and dynamic Actions. The interesting bit is, that we&#39;re able to use Web Source Modules for a DML form, although APEX 18.1 does not provide declarative support so far. Using a bit of additional meta data and some custom PL/SQL code using the APEX_EXEC package we&#39;re able to build the form processes without using any manual HTTP or JSON handling code.</p> Carsten Czarski https://blogs.oracle.com/apex/creating-a-crud-form-on-a-rest-service-with-apex-181 Mon Jul 16 2018 07:15:14 GMT-0400 (EDT) Creating a CRUD form on a REST Service with APEX 18.1 https://blogs.oracle.com/apex/creating-a-crud-form-on-a-rest-service-with-apex-181 <p>In this blog posting we will highlight the new REST capabilities of Application Express 18.1 once more. This time we will show how to create a form to insert, update or delete rows - but not from a table, the form will work on a REST service instead.</p> <p>APEX 18.1 provides declarative support to build components on top of a REST service. However, only&nbsp;<em>Read Only</em>&nbsp;components like like reports or charts can use Web Source Modules directly; there is no wizard to create a form on a Web Source Module.</p> <p>So we have to implement some custom PL/SQL code in order to build a DML form on a REST service. As this blog posting shows, Web Source Modules can still do a lot of the work for us: <em>We will still be able to use the <strong>APEX_EXEC</strong> package - no manual JSON parsing will be required and we won&#39;t have to do any manual HTTP request.</em></p> <p>Note that full declarative support for Read/Write components like Forms or the Interactive Grid is planned for one of the next releases of Application Express - when that is available, you will be able to create a Form on a REST service directly, without any manual work at all - as you can do today with a report.</p> Provide a REST Service: Using ORDS Auto-REST <p>First we need the REST Service to work on. For this blog posting we will use the well-known EMP table and the <a href="https://docs.oracle.com/database/ords-18.1/AELIG/developing-REST-applications.htm#AELIG90103" target="_blank">&quot;Auto-REST&quot; feature of Oracle REST Data Services</a>. The most easy approach is to navigate to SQL Workshop &gt; SQL Commands and to execute the following simple PL/SQL Block:</p> begin ords.enable_schema; ords.enable_object( p_object =&gt; &#39;EMP&#39; ); end; / <p>Then, to check whether the REST Service works, try to execute the REST Service using a browser or the &quot;curl&quot; command line utility. Use the URL: <strong>http://{ords-server}:{port}/ords/{schema}/emp/.&nbsp;</strong>&nbsp;With a browser, the response should look as follows:</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/1d3ffe47b352ea657c7d0b8baf700bb0/bildschirmfoto_2018_07_16_um_10_15_31.png" style="width: 1932px; height: 1170px;" /></p> Create the APEX Web Source Module <p>Then, head over to Application Express, log into your workspace and create an application. Navigate to <strong>Shared Components</strong> and lookup <strong>Web Source Modules</strong>. In a new application, this section is empty. Click the&nbsp;<strong>Create</strong>&nbsp;button in order to create a new Web Source Module <strong>from Scratch</strong>.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/53c9046001d4ae589ac610e1dd114dfb/bildschirmfoto_2018_07_16_um_10_17_15.png" style="width: 2600px; height: 844px;" /></p> <p>Choose <strong>Oracle REST Data Services</strong> as the <strong>Web Source Type</strong>, provide the <strong>URL endpoint</strong> and click <strong>Next</strong>.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/07445b157b4f33ab41578ae277f45eca/bildschirmfoto_2018_07_16_um_10_17_41.png" style="width: 1648px; height: 986px;" /></p> <p>Just click the <strong>Next</strong> button in the following wizard step for the <strong>Remote Server</strong>. In the <strong>Authentication</strong> step, simply hit the <strong>Discover</strong> button. You should see the following screen, which indicates that APEX can talk to the REST service.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/1ec46e498c05f6480ca9a01874f4b07f/bildschirmfoto_2018_07_16_um_10_17_54.png" style="width: 1598px; height: 958px;" />Click&nbsp;<strong>Create Web Source Module</strong>&nbsp;in order to save REST service meta data. You will be navigated back to the list of web source modules.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/0b47645e3040da9ae626730b46638a0d/bildschirmfoto_2018_07_16_um_10_23_23.png" style="width: 2160px; height: 662px;" /></p> Create a report on top of the Web Source Module <p>Then create a classic report on that Web Source module, as described in the<span>&nbsp;<a href="https://blogs.oracle.com/apex/get-started-with-rest-services-in-application-express-52-ea-1">Application Express Early Adopter: REST Services!</a> </span>blog posting. You can also use page designer: Drag a classic report region onto your page and change the&nbsp;<strong>Source</strong>&nbsp;attributes in the property pane on the right to use the new Web Source Module.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/e060fcd4a0015d14ce2ea7b2d0e21d48/bildschirmfoto_2018_07_16_um_10_18_53.png" style="width: 2988px; height: 1332px;" />Run the page. You should see the data from the EMP table - which actually comes from a REST service.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/ad996b9b3fc3428639cef4891b87a0da/bildschirmfoto_2018_07_16_um_10_19_12.png" style="width: 1788px; height: 1654px;" /></p> <p>This was the read only part. Now we&#39;ll get to the read / write part of the story.&nbsp;</p> Insert, Update or Delete on a REST Service <p>When we REST-Enabled the EMP table (with <strong>ORDS.ENABLE_OBJECT</strong>), not only a GET REST Service had been created. ORDS also provides REST Services to perform DML (insert, update or delete) rows.</p> <ul> <li><strong>INSERT</strong>:<br /> POST Request to <strong>http://{server}:{port}/ords/{schema}/emp/</strong>.<br /> The request body contains the data for the new row in JSON format.</li> <li><strong>UPDATE</strong>:<br /> PUT Request to <strong>http://{server}:{port}/ords/{schema}/emp/{empno}</strong>.<br /> The request body contains the data for the new row in JSON format.</li> <li><strong>DELETE</strong>:<br /> DELETE Request to <strong>http://{server}:{port}/ords/{schema}/emp/{empno}</strong>.<br /> The request body must be empty.</li> </ul> <p>Let&#39;s first try that with the &quot;curl&quot; command line utility (which is always a good tool to test our understanding of a REST service). The following <strong>curl</strong> invocation creates a new row by executing a POST request.</p> curl -H&quot;Content-Type:application/json&quot; \ -X POST \ -d&#39;{&quot;empno&quot;:4711,&quot;ename&quot;:&quot;APEX&quot;,&quot;job&quot;:&quot;DEV&quot;,&quot;hiredate&quot;:&quot;2001-01-01T20:00:00Z&quot;,&quot;sal&quot;:10,&quot;comm&quot;:null,&quot;deptno&quot;:10,&quot;mgr&quot;:7839}&#39; \ http://localhost:28080/ords/testit/emp/ <p>You should see the following resonse, indicating that the operation was successful.</p> {&quot;empno&quot;:4711,&quot;ename&quot;:&quot;APEX&quot;,&quot;job&quot;:&quot;DEV&quot;,&quot;mgr&quot;:7839,&quot;hiredate&quot;:&quot;2001-01-01T20:00:00Z&quot;,&quot;sal&quot;:10,&quot;comm&quot;:null,&quot;deptno&quot;:10,&quot;links&quot;:[{&quot;rel&quot;:&quot;self&quot;,&quot;href&quot;:&quot;http://localhost:28080/ords/testit/emp/4711&quot;},{&quot;rel&quot;:&quot;edit&quot;,&quot;href&quot;:&quot;http://localhost:28080/ords/testit/emp/4711&quot;},{&quot;rel&quot;:&quot;describedby&quot;,&quot;href&quot;:&quot;http://localhost:28080/ords/testit/metadata-catalog/emp/item&quot;},{&quot;rel&quot;:&quot;collection&quot;,&quot;href&quot;:&quot;http://localhost:28080/ords/testit/emp/&quot;}]} <p>We can also check by querying the table directly:</p> SQL&gt; select * from emp; EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO ------- -------- ------------- ---- ---------------------- ----- ------ -------- 7369 SMITH CLERK 7902 17.12.1980 00:00:00 800 20 7499 ALLEN SALESMAN 7698 20.02.1981 00:00:00 1600 300 30 7521 WARD SALESMAN 7698 22.02.1981 00:00:00 1250 500 30 7566 JONES MANAGER 7839 02.04.1981 00:00:00 2975 20 7654 MARTIN SALESMAN 7698 28.09.1981 00:00:00 1250 1400 30 7698 BLAKE MANAGER 7839 01.05.1981 00:00:00 2850 30 7782 CLARK MANAGER 7839 09.06.1981 00:00:00 2450 10 7788 SCOTT ANALYST 7566 09.12.1982 00:00:00 3000 20 7839 KING PRESIDENT 17.11.1981 00:00:00 5000 10 7844 TURNER SALESMAN 7698 08.09.1981 00:00:00 1500 0 30 7876 ADAMS CLERK 7788 12.01.1983 00:00:00 1100 20 7900 JAMES CLERK 7698 03.12.1981 00:00:00 950 30 7902 FORD ANALYST 7566 03.12.1981 00:00:00 3000 20 7934 MILLER CLERK 7782 23.01.1982 00:00:00 1300 10 <b> 4711 APEX DEV 7839 01.01.2001 12:00:00 10 10 </b> <p>Since we now know, how to call the POST, PUT and DELETE REST Services, let&#39;s prepare the already existing Web Source Module and then build the CRUD form.</p> Prepare the Web Source Module for CRUD operations <p>Since APEX 18.1 does not provide declarative support for Forms on a Web Source Module, we must provide some information ourselves, but we can still leverage Web Source Modules and let APEX do a lot of low-level work for us.</p> <p>Look up your new web source module in <strong>Shared Components</strong>. First, navigate to the <strong>Advanced</strong> tab and note down the exact <strong>Static ID </strong>value of the Web Source Module (here:&nbsp;<strong>Auto_REST_Service_EMP</strong>).&nbsp;We&#39;ll need that later on.<img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/584b104cb4f8eb5bbcb85f5474200896/bildschirmfoto_2018_07_16_um_11_00_12.png" style="width: 2354px; height: 794px;" />​</p> <p>&nbsp;</p> <p>&nbsp;</p> <p>Then select the <strong>Operations</strong> tab.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/b1dffe8c88794769c016be997f82988b/bildschirmfoto_2018_07_16_um_10_41_12.png" style="width: 2738px; height: 1130px;" /></p> <p>We can see that APEX already did some work for us. Since this is an ORDS REST Service, APEX detected, that URL endpoints for POST, PUT and DELETE exist and it added these to the REST Service meta data.</p> Remove the unneeded DELETE operation <p>ORDS provides indeed two DELETE endpoints: One is to delete a single row, the other one to delete the whole collection (i.e. all rows from the table). We won&#39;t need the latter one in our APEX application. So click the yellow pencil of the DELETE operation which has <em>no value</em> in the <strong>Database Operation</strong> column and remove that operation by clicking the <strong>Delete</strong> button.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/77b4a02540536b56c1a85939c3e14d4f/bildschirmfoto_2018_07_16_um_10_41_12.png" style="width: 2738px; height: 1130px;" /></p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/d1ee3d850ec3804177fb9e3b0068e784/bildschirmfoto_2018_07_16_um_11_47_42.png" style="width: 2344px; height: 926px;" /></p> Changes to the POST operation <p>Then, click the pencil to edit the <strong>POST</strong> operation.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/cd8bd63d28d22248f96c01d1177a9b70/bildschirmfoto_2018_07_16_um_10_42_37.png" style="width: 2342px; height: 1290px;" />Provide the following JSON template as the <strong>Request Body Template</strong>.</p> {&quot;empno&quot;:#EMPNO#,&quot;ename&quot;:&quot;#ENAME#&quot;,&quot;job&quot;:&quot;#JOB#&quot;,&quot;hiredate&quot;:&quot;#HIREDATE#&quot;,&quot;sal&quot;:#SAL#,&quot;comm&quot;:#COMM#,&quot;deptno&quot;:#DEPTNO#,&quot;mgr&quot;:#MGR#} <p>Click Apply Changes and then the pencil again to come back to this form. Then click the <strong>Add Parameter</strong> button to open the Operation Parameter dialog.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/7c6cb79b286f868932e61b2484aeeed4/bildschirmfoto_2018_07_16_um_10_47_08.png" style="width: 2348px; height: 1048px;" /></p> <p>For each column name, which you have created a<strong> #PLACEHOLDER#</strong> for, add a Parameter of the <strong>Request / Response Body</strong> type.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/bf76a81c26220d84850b7e8c1d9dcab9/bildschirmfoto_2018_07_16_um_10_48_31.png" style="width: 2154px; height: 1046px;" />When finished, you should have eight Operation Parameters, one for each column of the EMP table. Then add another parameter of Type <strong>HTTP Header </strong>with<strong>&nbsp;</strong><strong>Content-Type</strong>&nbsp;as its name and <strong>application/json</strong>&nbsp;as the value. The <strong>Operation Parameters</strong> section for the POST operation should finally look as follows.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/afb3f50536bddaa951d954da7449ac64/bildschirmfoto_2018_07_16_um_10_51_00.png" /></p> Changes to the PUT operation. <p>For the PUT operation, provide the following <strong>JSON Request Body template</strong> (it&#39;s similar to the template for the POST operation, but without the EMPNO column).</p> {&quot;ename&quot;:&quot;#ENAME#&quot;,&quot;job&quot;:&quot;#JOB#&quot;,&quot;hiredate&quot;:&quot;#HIREDATE#&quot;,&quot;sal&quot;:#SAL#,&quot;comm&quot;:#COMM#,&quot;deptno&quot;:#DEPTNO#,&quot;mgr&quot;:#MGR#} <p>Then add Web Source Parameters as well, similar as done for the POST operations:</p> <ul> <li>One Parameter of type <strong>Request / Response body</strong> for each <strong>#PLACEHOLDER#</strong> in the JSON Request Template</li> <li>One static Parameter of type <strong>HTTP Header</strong> with <strong>Content-Type</strong> as the <strong>Name</strong> and <strong>application/json</strong> as the <strong>value</strong></li> <li>One Parameter of type&nbsp;<strong>URL Pattern variable</strong><span style="white-space:pre"> with name <strong>id</strong>.</span></li> </ul> <p><span style="white-space:pre">The Operation parameters section for the PUT operation should look as follows:</span></p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/82198165204ef4f6eb1ccb66db661090/bildschirmfoto_2018_07_16_um_12_06_16.png" style="width: 2532px; height: 1254px;" /></p> Changes to the DELETE operation <p>The remaining DELETE operation does not need any JSON Request template and only one parameter definition: Create a parameter of type <strong>URL pattern variable</strong> with name <strong>id</strong>.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/7c9ec7a7c45e18344bf98e716f54772b/bildschirmfoto_2018_07_16_um_12_01_56.png" style="width: 2552px; height: 828px;" /></p> <p>Now, the operations are all set and the Web Source Module has been prepared. We can continue building the form page.</p> Create the form page <p>Next, create a new page for the form on the REST service. Create a blank page and add a region containing eight items (one for each form element) to that page. When finished, your form might looks as follows (it has no functionality so far).</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/37181407e11560db90341c52b850c207/bildschirmfoto_2018_07_16_um_10_57_04.png" style="width: 2340px; height: 1100px;" />Next, we&#39;ll add functionality to populate the form with values on page load. We&#39;ll need do this using custom PL/SQL code and the <a href="https://docs.oracle.com/database/apex-18.1/AEAPI/APEX_EXEC.htm#AEAPI-GUID-3CF1D2DD-AEA4-4982-9857-548567AB7169" target="_blank"><strong>APEX_EXEC</strong></a> package. The blog posting&nbsp;<span> <a href="https://blogs.oracle.com/apex/apex-181-early-adopter-2-rest-services-and-plsql">APEX 18.1 Early Adopter 2: REST Services and PL/SQL</a> </span>contains a good template for our form loading process.&nbsp;</p> <p>In Page Designer, navigate to the Before Headers section in the page tree on the left and create a new Process.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/e5dff30292d767e8d97b0de6b50a6742/bildschirmfoto_2018_07_16_um_11_13_07.png" /></p> <p>Name the process <strong>Load REST Data</strong> and provide the following PL/SQL Code:</p> declare l_columns apex_exec.t_columns; l_context apex_exec.t_context; l_filters apex_exec.t_filters; type t_column_position is table of pls_integer index by varchar2(32767); l_column_position t_column_position; begin -- specify columns to select from the web source module apex_exec.add_column( p_columns =&gt; l_columns, p_column_name =&gt; &#39;EMPNO&#39;); apex_exec.add_column( p_columns =&gt; l_columns, p_column_name =&gt; &#39;ENAME&#39;); apex_exec.add_column( p_columns =&gt; l_columns, p_column_name =&gt; &#39;JOB&#39;); apex_exec.add_column( p_columns =&gt; l_columns, p_column_name =&gt; &#39;HIREDATE&#39;); apex_exec.add_column( p_columns =&gt; l_columns, p_column_name =&gt; &#39;MGR&#39;); apex_exec.add_column( p_columns =&gt; l_columns, p_column_name =&gt; &#39;SAL&#39;); apex_exec.add_column( p_columns =&gt; l_columns, p_column_name =&gt; &#39;COMM&#39;); apex_exec.add_column( p_columns =&gt; l_columns, p_column_name =&gt; &#39;DEPTNO&#39;); -- add a filter to query only the selected row apex_exec.add_filter( p_filters =&gt; l_filters, p_column_name =&gt; &#39;EMPNO&#39;, p_filter_type =&gt; apex_exec.c_filter_eq, p_value =&gt; to_number( :P2_EMPNO ) ); -- invoke Web Source Module and select data l_context := apex_exec.open_web_source_query( p_module_static_id =&gt; &#39;Auto_REST_Service_EMP&#39;, p_filters =&gt; l_filters, p_columns =&gt; l_columns ); -- now get result set positions for the selected columns for c in 1 .. l_columns.count loop l_column_position( l_columns( c ).name ) := apex_exec.get_column_position( l_context, l_columns( c ).name ); end loop; -- if we have a result set, set the form items if apex_exec.next_row( l_context ) then :P2_ENAME := apex_exec.get_varchar2( l_context, l_column_position( &#39;ENAME&#39; ) ); :P2_JOB := apex_exec.get_varchar2( l_context, l_column_position( &#39;JOB&#39; ) ); :P2_HIREDATE := apex_exec.get_varchar2( l_context, l_column_position( &#39;HIREDATE&#39; ) ); :P2_SAL := apex_exec.get_number ( l_context, l_column_position( &#39;SAL&#39; ) ); :P2_COMM := apex_exec.get_number ( l_context, l_column_position( &#39;COMM&#39; ) ); :P2_MGR := apex_exec.get_number ( l_context, l_column_position( &#39;MGR&#39; ) ); :P2_DEPTNO := apex_exec.get_number ( l_context, l_column_position( &#39;DEPTNO&#39; ) ); -- otherwise raise NO_DATA_FOUND else raise no_data_found; end if; -- finally: release all resources apex_exec.close( l_context ); exception when others then -- IMPORTANT: also release all resources, when an exception occcurs! apex_exec.close( l_context ); raise; end; <p>Add a server-side condition to have the process only executed when the <strong>P2_EMPNO</strong> item<strong> IS NOT NULL</strong>, then&nbsp;save your changes.</p> <p>Let&#39;s now test whether this PL/SQL code already works. Navigate back to the report page and change the <strong>EMPNO</strong> column of the report to be rendered as a link to the new form page.&nbsp;</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/1f76048a45f98f1d76b74821d76d1910/bildschirmfoto_2018_07_16_um_11_15_44.png" style="width: 2760px; height: 1542px;" /></p> <p>Run the report page - you should now see links in the <strong>EMPNO</strong> column.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/aff0b19f883b9aef3a4c2063fa2f2752/bildschirmfoto_2018_07_16_um_11_17_06.png" style="width: 1238px; height: 1158px;" /></p> <p>Then add a button to the report page which allows to create a new row.</p> <ul> <li><strong>Button Name</strong>: CREATE_NEW</li> <li><strong>Button Label</strong>: Create New</li> <li><strong>Button Action</strong>: Redirect to Page</li> <li><strong>Target</strong>: Page 2 (the form page); set <strong>Clear Cache</strong> for page 2 (the form page)</li> </ul> <p>When clicking the link in the <strong>EMPNO</strong> column, the form page should be loaded and populated with the values for the selected row; when clicking the <strong>Create New</strong> button, an empty form should be loaded.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/e9503fa4afeab015db84e7580f1c70be/bildschirmfoto_2018_07_16_um_11_17_14.png" style="width: 2326px; height: 976px;" />This&nbsp;concludes the first part of the form page. We loaded data from the REST service into the page items without using any <strong>APEX_WEB_SERVICE</strong> call and without doing any manual JSON parsing.</p> Add DML processes to the form <p>Before adding the PL/SQL code to process POST, PUT and DELETE requests add the required buttons to the page:</p> <ul> <li><strong>CREATE</strong> with an&nbsp;<strong>IS NULL</strong> condition for the&nbsp;<strong>P2_ENAME&nbsp;</strong>item</li> <li><strong>APPLY_CHANGES</strong> with the<strong>&nbsp;IS NOT NULL</strong> condition for the&nbsp;<strong>P2_ENAME </strong>item</li> <li><strong>DELETE&nbsp;</strong>with the<strong>&nbsp;IS NOT NULL</strong>&nbsp;condition for the&nbsp;<strong>P2_ENAME&nbsp;</strong>item</li> </ul> <p>The page should then look as follows:</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/6d8e9e1a1aea2d680aa06973b1b1e373/bildschirmfoto_2018_07_16_um_11_22_05.png" style="width: 2356px; height: 1086px;" /></p> <p>Now let&#39;s add the PL/SQL Code to process the INSERT, UPDATE or DELETE operations. We have provided all required meta data in the Web Source Modules and we can thus work with the APEX_EXEC package alone. Dependent on the button clicked, the PL/SQL code will prepare parameters for the Web Source Module operation and finally call <a href="https://docs.oracle.com/database/apex-18.1/AEAPI/EXECUTE_WEB_SOURCE-Procedure.htm#AEAPI-GUID-30272C98-EA7B-4220-A26B-63DFF9DFCD1F" target="_blank">APEX_EXEC.PROCESS_WEB_SOURCE</a>.&nbsp;</p> <p>In Page Designer, create a new PL/SQL process in the Processing section.</p> <p><img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/3c9574bd82c2cc360a4c3d6860f95491/bildschirmfoto_2018_07_16_um_12_14_51.png" style="width: 1958px; height: 1188px;" /></p> <p>Name it <strong>Process REST DML</strong> and provide the following PL/SQL code:</p> declare l_parameters apex_exec.t_parameters; begin -- add the primary key value as the &quot;id&quot; parameter; this will be appended to the URL for DELETE and APPLY_CHANGES if :REQUEST in ( &#39;DELETE&#39;, &#39;APPLY_CHANGES&#39; ) then apex_exec.add_parameter( p_parameters =&gt; l_parameters, p_name =&gt; &#39;id&#39;, p_value =&gt; :P2_EMPNO ); end if; -- add form item values as parameters for CREATE and APPLY_CHANGES if :REQUEST in ( &#39;CREATE&#39;, &#39;APPLY_CHANGES&#39; ) then apex_exec.add_parameter( p_parameters =&gt; l_parameters, p_name =&gt; &#39;ENAME&#39;, p_value =&gt; :P2_ENAME ); apex_exec.add_parameter( p_parameters =&gt; l_parameters, p_name =&gt; &#39;EMPNO&#39;, p_value =&gt; :P2_EMPNO ); apex_exec.add_parameter( p_parameters =&gt; l_parameters, p_name =&gt; &#39;JOB&#39;, p_value =&gt; :P2_JOB ); apex_exec.add_parameter( p_parameters =&gt; l_parameters, p_name =&gt; &#39;HIREDATE&#39;, p_value =&gt; to_char( to_date( :P2_HIREDATE ), &#39;YYYY-MM-DD&#39; ) || &#39;T00:00:00Z&#39; ); apex_exec.add_parameter( p_parameters =&gt; l_parameters, p_name =&gt; &#39;SAL&#39;, p_value =&gt; :P2_SAL ); apex_exec.add_parameter( p_parameters =&gt; l_parameters, p_name =&gt; &#39;COMM&#39;, p_value =&gt; coalesce( :P2_COMM, &#39;null&#39; ) ); apex_exec.add_parameter( p_parameters =&gt; l_parameters, p_name =&gt; &#39;MGR&#39;, p_value =&gt; :P2_MGR ); apex_exec.add_parameter( p_parameters =&gt; l_parameters, p_name =&gt; &#39;DEPTNO&#39;, p_value =&gt; :P2_DEPTNO ); end if; -- invoke Web Source Module for and select data apex_exec.execute_web_source( p_module_static_id =&gt; &#39;Auto_REST_Service_EMP&#39;, p_operation =&gt; case :REQUEST when &#39;APPLY_CHANGES&#39; then &#39;PUT&#39; when &#39;CREATE&#39; then &#39;POST&#39; when &#39;DELETE&#39; then &#39;DELETE&#39; end, p_parameters =&gt; l_parameters ); end; <p>As <strong>Server-Side condition</strong>, choose <strong>Request is contained in value</strong> and provide&nbsp;<strong>CREATE:APPLY_CHANGES:DELETE</strong> as the Value. That makes sure that the code is only called when one of the three buttons has been clicked. Finally provide a nice success message and add a branch back to the report page (here: page 1).</p> <p>Now we can test the CRUD form:</p> <ul> <li>Click the <strong>Create New</strong> button below the report, enter some data and save a new row<br /> <img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/42ba92c51e8c68a58c53b959133120b2/bildschirmfoto_2018_07_16_um_12_44_52.png" style="width: 2536px; height: 1042px;" /><br /> <img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/5ce05ddfa281f3526332d39368dd1cb4/bildschirmfoto_2018_07_16_um_12_45_07.png" /></li> <li>Update the <strong>Name</strong> value of that new row<br /> <img alt="" src="https://cdn.app.compendium.com/uploads/user/e7c690e8-6ff9-102a-ac6d-e4aebca50425/fbd61610-2cfe-4a98-b117-958129af0c39/Image/055805d3ad0ead173c650984efc2bca2/bildschirmfoto_2018_07_16_um_12_45_21.png" style="width: 2508px; height: 712px;" /></li> </ul> <p>Of course, this form can be further extended - think about validations, additional processes and dynamic Actions. The interesting bit is, that we&#39;re able to use Web Source Modules for a DML form, although APEX 18.1 does not provide declarative support so far. Using a bit of additional meta data and some custom PL/SQL code using the APEX_EXEC package we&#39;re able to build the form processes without using any manual HTTP or JSON handling code.</p> Carsten Czarski https://blogs.oracle.com/apex/creating-a-crud-form-on-a-rest-service-with-apex-181 Mon Jul 16 2018 07:15:14 GMT-0400 (EDT) I'll be at APEX Meetup Munich: Thu 19 Jul 2018 http://dgielis.blogspot.com/2018/07/ill-be-at-apex-meetup-munich-thu-19-jul.html Just a quick note I'll do two presentations at the <a href="https://www.meetup.com/orclapex-muc/events/251924260/">APEX Meetup in Munich</a> on Thursday, July 19th 2018.<br /><br />In the first presentation I'll bring you to a virtual and augmented world, entirely build in Oracle Application Express (<a href="https://apex.oracle.com/">APEX</a>). There are 30 Google Cardboards available to make the experience complete. Fun guaranteed! :)<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-9xEsabnzpvc/W0sncujUxaI/AAAAAAAAJTM/6Elyq0oxcBMEvHtoe7AfSdQLwOuIRFAGACLcBGAs/s1600/Screen%2BShot%2B2018-07-15%2Bat%2B12.50.19.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="815" data-original-width="1600" height="324" src="https://4.bp.blogspot.com/-9xEsabnzpvc/W0sncujUxaI/AAAAAAAAJTM/6Elyq0oxcBMEvHtoe7AfSdQLwOuIRFAGACLcBGAs/s640/Screen%2BShot%2B2018-07-15%2Bat%2B12.50.19.png" width="640" /></a></div><br />At KScope I was also interviewed by Bob Rhubart on my talks over there, which the AR/VR presentation was one of them.<br /><div style="text-align: center;"><br /></div><div style="text-align: center;"><iframe allow="autoplay; encrypted-media" allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/tOo5aqHkQVQ" width="560"></iframe></div><br />In my second presentation at Munich I'll show the upcoming version of <a href="https://www.apexofficeprint.com/">APEX Office Print (AOP)</a>.<br />I'll show some features nobody has seen before :) With every major release of AOP I feel like this:<br /><div style="text-align: center;"><br /></div><div style="text-align: center;"><iframe allow="autoplay; encrypted-media" allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/iSiwftMMKvo" width="560"></iframe></div><br />If you are in the Munich area I would love to meet you at the meetup.<br /><br /> Dimitri Gielis tag:blogger.com,1999:blog-21122514.post-4020832832656499380 Sun Jul 15 2018 07:14:00 GMT-0400 (EDT) My top 5 APEX 18.1 Plug-ins http://dgielis.blogspot.com/2018/07/my-top-5-apex-181-plugins.html <div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-LfRA_7IWvHs/W0mtXO6ngdI/AAAAAAAAJRY/i7MeEL38kh4ZIAY02E86i7OECIZLGAMFACLcBGAs/s1600/plugins.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="206" data-original-width="300" height="137" src="https://3.bp.blogspot.com/-LfRA_7IWvHs/W0mtXO6ngdI/AAAAAAAAJRY/i7MeEL38kh4ZIAY02E86i7OECIZLGAMFACLcBGAs/s200/plugins.png" width="200" /></a></div>With every new version of <a href="https://apex.oracle.com/">Oracle Application Express (APEX)</a> new features are added and the life of a developer is made even easier. If the feature set is not enough or you see you need to build the same functionality more often, you can always extend APEX with <a href="https://docs.oracle.com/database/apex-18.1/HTMDB/implementing-plug-ins.htm#HTMDB27001">plug-ins</a>.<br /><br />There are <b>six different types of plug-ins</b>: dynamic action, item,&nbsp;&nbsp;region, process, authentication scheme and authorization scheme.<br /><br />Plug-ins are absolutely fantastic to <b>extend the native functionalities of APEX</b> in a declarative way. The APEX plug-in becomes a declarative option in the APEX Builder and has the [Plug-in] text next to it. In the next screenshot, you see the dynamic actions being extended by two Plug-ins.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-Oo3dHCahTD4/W0m1lfkWCwI/AAAAAAAAJSA/Kc0S8d7v4k0tME7sjP9b67ptdU4s_dc9wCLcBGAs/s1600/Screen%2BShot%2B2018-07-14%2Bat%2B10.33.23.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="568" data-original-width="1600" height="141" src="https://2.bp.blogspot.com/-Oo3dHCahTD4/W0m1lfkWCwI/AAAAAAAAJSA/Kc0S8d7v4k0tME7sjP9b67ptdU4s_dc9wCLcBGAs/s400/Screen%2BShot%2B2018-07-14%2Bat%2B10.33.23.png" width="400" /></a></div><br />If you are <b>searching for an APEX plug-in</b>, I typically go to <a href="https://apex.world/ords/f?p=100:700:0">APEX World &gt; Plug-ins</a>. The nice thing about that site is that the plug-ins seem to be maintained, so if a plug-in is not supported anymore it gets the status deprecated.<br /><br />!! And here lays the <b>catch with using plug-ins</b>. When you decide to use a plug-in in your project, you become responsible for this and need to make sure it's compatible with every release of Oracle APEX. Many plug-ins are open source and many plug-in developers maintain their plug-ins, but it's really important you understand that at the end you are responsible for things you put in your application. If the plug-in is not secure or it breaks in the next release of APEX, you need to find a solution. So use plug-ins with care and see for example how many likes the plug-in has or what the comments are about the plug-in or author. Oracle is not reviewing or supporting the plug-ins !!<br /><br />When I saw the tweet of Travis, I thought to do a blog post on my <b>top 5 plug-ins</b> I use in almost every project.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-c1jdAw9XtYc/W0mtW6Xzz8I/AAAAAAAAJRg/_PnaomT7RckUGQI2Ch2bMnXaQNpDoPPGwCEwYBhgL/s1600/tweet.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="248" data-original-width="600" height="132" src="https://3.bp.blogspot.com/-c1jdAw9XtYc/W0mtW6Xzz8I/AAAAAAAAJRg/_PnaomT7RckUGQI2Ch2bMnXaQNpDoPPGwCEwYBhgL/s320/tweet.png" width="320" /></a></div><br />Here we go:<br /><br />1. <a href="https://github.com/Dani3lSun/apex-plugin-builtwithlove/releases">Built with love using Oracle APEX</a><br /><br />I'm proud to built applications with Oracle Application Express, and this plug-in makes it very clear :) At the bottom of the app, you will see this text:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-9-VH8704KFc/W0mzDPzm-vI/AAAAAAAAJRs/4YJHtf15ZbsUfjq_eEgNdu1mYyBNhXlpQCLcBGAs/s1600/f.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="72" data-original-width="442" height="31" src="https://4.bp.blogspot.com/-9-VH8704KFc/W0mzDPzm-vI/AAAAAAAAJRs/4YJHtf15ZbsUfjq_eEgNdu1mYyBNhXlpQCLcBGAs/s200/f.gif" width="200" /></a></div><br />Note that in Oracle APEX 18.1 this text in included by default and you don't even need to add the plug-in. Nevertheless, I wanted to include it in this list as it should be there in every app, even the ones built before APEX 18.1 :)<br /><br />2. <a href="https://github.com/nbuytaert1/apex-select2/releases">Select2</a><br /><br />When a select list (or drop-down) has many values, it takes too long to find the right value. Select2 makes it easy to search for values, it also supports lazy loading and multiple select.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-CzmEs5Ckqbg/W0mzrNvFXvI/AAAAAAAAJR0/a1dlYPpHw-I020GloKCMe4sNPZWu2gddACLcBGAs/s1600/f.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="281" data-original-width="314" height="178" src="https://3.bp.blogspot.com/-CzmEs5Ckqbg/W0mzrNvFXvI/AAAAAAAAJR0/a1dlYPpHw-I020GloKCMe4sNPZWu2gddACLcBGAs/s200/f.png" width="200" /></a></div><br />3. <a href="https://www.apexofficeprint.com/">APEX Office Print</a><br /><br />APEX Office Print extends APEX so it becomes possible to export to native Excel files and generate documents in Word, Powerpoint, PDF, HTML and Text, all based on your own template. It has many more features, I <a href="http://dgielis.blogspot.com/2018/06/how-to-export-to-excel-and-print-to-pdf.html">blogged</a> about some before.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-fygf2mOLzJI/W0nVLSfczLI/AAAAAAAAJS0/Hw7h9y7yfbMMvnHzn1JkZrXZaNCKrgI1ACLcBGAs/s1600/export_excel_pdf.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="804" data-original-width="1331" height="241" src="https://3.bp.blogspot.com/-fygf2mOLzJI/W0nVLSfczLI/AAAAAAAAJS0/Hw7h9y7yfbMMvnHzn1JkZrXZaNCKrgI1ACLcBGAs/s400/export_excel_pdf.gif" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><br />4. <a href="https://github.com/Dani3lSun/apex-plugin-dropzone/releases">Dropzone</a><br /><br />APEX 18.1 has declarative multi-file upload, but still, I love the Dropzone plug-in developed by Daniel&nbsp;Hochleitner. You can drag multiple files from your desktop straight in your APEX app. Daniel is one of my favorite plug-in developers. When he releases something, you know it will be good.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-xLugbXaQpA8/W0m_GXfjQ5I/AAAAAAAAJSM/UexgNxLqzbkzA093nw9nCsA8pvwJO7POgCLcBGAs/s1600/f-1.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="825" data-original-width="1600" height="206" src="https://1.bp.blogspot.com/-xLugbXaQpA8/W0m_GXfjQ5I/AAAAAAAAJSM/UexgNxLqzbkzA093nw9nCsA8pvwJO7POgCLcBGAs/s400/f-1.gif" width="400" /></a></div><br /><br />5. <a href="https://github.com/mennooo/orclapex-modal-lov/releases">Modal LOV</a><br /><br />This is a newer plug-in and I haven't used it that much yet, but I'm sure I will do. The nice thing with this item type plug-in is that it also supports Interactive Grid. Where Select2 stays within the page, this Modal LOV comes with a modal list of values (pop-up) which is great if you want to show multiple columns or need more context for the record you need to select.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-46zbNq8weXQ/W0nAIpVcuTI/AAAAAAAAJSU/JDFlQBA7uYgWBdsHE9ZBBFOBpQDsy4qFQCLcBGAs/s1600/preview.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="787" data-original-width="932" height="270" src="https://3.bp.blogspot.com/-46zbNq8weXQ/W0nAIpVcuTI/AAAAAAAAJSU/JDFlQBA7uYgWBdsHE9ZBBFOBpQDsy4qFQCLcBGAs/s320/preview.gif" width="320" /></a></div><br />There are many more plug-ins out there, most of them work on APEX 5.x and upwards. For example, <a href="http://apex.pretius.com/apex/f?p=PLUGINS:HOME:::NO:::">Pretius</a> has some cool plug-ins too, the one to create nested reports I recently used in a project. Another site you can find plug-ins is&nbsp;<a href="http://www.apex-plugin.com/">APEX-Plugin.com</a>.<br /><br /> Dimitri Gielis tag:blogger.com,1999:blog-21122514.post-4112314467599675494 Sat Jul 14 2018 06:46:00 GMT-0400 (EDT) Autonomous Blockchain, It’s Almost Here! https://insum.ca/autonomous-blockchain-its-almost-here/ <p>ICYMI (in case you missed it), Oracle is having a special <a href="https://go.oracle.com/LP=71386" target="_blank" rel="noopener">live webcast</a> on July 16, 2018. After several false expectations from the media, Oracle&#8217;s finally (probably) announcing the general availability of the <a href="https://cloud.oracle.com/blockchain" target="_blank" rel="noopener">Autonomous Blockchain</a> service.</p> <p>I have been longing for the day!</p> <p>At <a href="https://kscope18.odtug.com/" target="_blank" rel="noopener">Kscope18</a>, I had the honour of presenting on how Blockchain technology could be relevant to an Oracle <a href="https://apex.oracle.com/en/" target="_blank" rel="noopener">Application Express</a> (APEX) developer. With huge leaps in how APEX supports REST services, especially in the recent 18.1 release (read <a href="https://twitter.com/cczarski" target="_blank" rel="noopener">Carsten Czarski&#8217;s</a> <a href="https://blogs.oracle.com/apex/quick-and-easy-twitter-api-with-apex-181" target="_blank" rel="noopener">blog post</a> on how easy it is to integrate REST services in APEX), the APEX developer community is strongly positioned to capitalize on the potential that Blockchain brings to the applications we write.</p> <p>My session focused on two popular Blockchain technologies: <a href="https://ethereum.org/" target="_blank" rel="noopener">Ethereum</a> and <a href="https://www.hyperledger.org/projects/fabric" target="_blank" rel="noopener">Hyperledger Fabric</a> (HF). They represent a &#8220;permissionless&#8221; and &#8220;permissioned&#8221; blockchain respectively, with the latter being more relevant to the industry and natively more secure.</p> <h2>Hyperledger Fabric is the Cornerstone</h2> <p>If you have been watching developments in the blockchain arena, you will know that HF is a front-runner and will be the cornerstone of their Autonomous Blockchain product offering. From the information I have gleaned, we can anticipate a comprehensive and easy to use user interface (UI) for managing a HF network. Aside from management tools, we can expect a UI for compiling and deploying <a href="http://hyperledger-fabric.readthedocs.io/en/latest/chaincode.html" target="_blank" rel="noopener">chaincode</a>, and REST APIs that developers can build against.</p> <p>Unfortunately, there was so much to talk about during my presentation, that I ran out of time as anticipated. I was not able to demonstrate and explain how I created a proof-of-concept application using APEX and HF.</p> <p>&nbsp;</p> <p><img class="alignnone wp-image-11962 size-full" src="https://insum.ca/wp-content/uploads/2018/07/tndemo.gif" alt="Autonomous Blockchain it's almost here!" width="1377" height="802" /></p> <p>I will be repeating my Kscope18 presentation later in August. If you are interested to listen to the extended version of my session, please register your interest using this <a href="http://info.insum.ca/webinar-signup" target="_blank" rel="noopener">link</a>, so that we can inform you when registrations are open.</p> <h2>A quick Overview of Hyperledger Fabric</h2> <p>Meanwhile, in anticipation of a launch announcement, I&#8217;d like to share a quick overview on how you could start looking at integrating HF with your applications.</p> <p>The <a href="http://hyperledger.org/" target="_blank" rel="noopener">Hyperledger</a> is a huge and growing consortium of large and small companies interested in developing next-generation frameworks for creating usable blockchains. It comes under the umbrella of the <a href="https://www.linuxfoundation.org/" target="_blank" rel="noopener">Linux Foundation</a> and works very similarly to the more matured <a href="https://www.apache.org/" target="_blank" rel="noopener">Apache Foundation</a>.</p> <p>There are many frameworks that the community has already developed, but the most prominent is Hyperledger Fabric. To make it easier for developers to create blockchain applications, the consortium created the Hyperledger Composer (Composer) tool.</p> <h2>Four Key Concepts</h2> <p>With Composer, developers, in collaboration with business owners, create a business network. It contains four key concepts:</p> <ul> <li>Model &#8211; a file that defines the assets, participants and transactions that are involved</li> <li>Script &#8211; a file that contains the transaction (business) logic and is written in JavaScript</li> <li>Access Control &#8211; a single ACL file that determines what participants can do on the business network</li> <li>Query &#8211; a file with query definitions.</li> </ul> <p>These are packaged and deployed on a HF network using either command line interface (CLI) tools or the <a href="https://hyperledger.github.io/composer/latest/playground/playground-index" target="_blank" rel="noopener">Composer Playground</a>. The latter is an easy to deploy and use web application that helps developers create, test and deploy business networks. To get a feel of what it is, check out IBM&#8217;s demo <a href="http://composer-playground.mybluemix.net/" target="_blank" rel="noopener">playground</a>. Note that using Playground, you can create blockchains that run entirely off your browser&#8217;s local storage. But, be sure to export and save your hard work!</p> <p>You can simulate interactions with the blockchain using the Playground, but the real proof of the pudding is to have your APEX applications interact directly with the blockchain. And that&#8217;s where REST comes in. Along with Composer, a simple <a href="https://www.npmjs.com/" target="_blank" rel="noopener">npm</a> install supplies a <a href="https://hyperledger.github.io/composer/latest/integrating/getting-started-rest-api" target="_blank" rel="noopener">utility</a> to restify the business network. It even generates a <a href="https://swagger.io/" target="_blank" rel="noopener">Swagger</a> document that provides all you need to know on making REST calls against the blockchain.</p> <h2>Autonomous Blockchain more Robust</h2> <p>A side note. At Kscope18, I attended <a href="https://twitter.com/EmanAbio" target="_blank" rel="noopener">Emmanuel Abiodun</a>&#8216;s session on an introduction to Hyperledger technologies. Emmanuel&#8217;s an expert in blockchains. I was grateful to have a brief discussion on how &#8220;production-ready&#8221; Composer is for prime time. It&#8217;s a useful POC tool, but I think we can expect Oracle to provide a more robust platform with their Autonomous Blockchain service.</p> <p>APEX is future (and <a href="https://joelkallman.blogspot.com/2018/05/is-apex-suitable-for-enterprise-setting.html" target="_blank" rel="noopener">enterprise</a>) ready! Be even more prepared by starting to look at emerging technologies like Blockchains. HF has gone through a few major releases now, and using <a href="https://www.docker.com/" target="_blank" rel="noopener">Docker</a>, you can stand up a HF network even on your laptop! I&#8217;ll share more on the development process in August. Or if you can&#8217;t wait, please look <a href="https://twitter.com/fuzziebrain" target="_blank" rel="noopener">me</a> up on Twitter or drop me a note below.</p> <p>So, &#8220;See you&#8221; at Monday&#8217;s webcast!</p> <p>Want to learn more about APEX applications? <a href="https://insum.ca/contact/" target="_blank" rel="noopener">Contact us!</a></p> <p>The post <a rel="nofollow" href="https://insum.ca/autonomous-blockchain-its-almost-here/">Autonomous Blockchain, It&#8217;s Almost Here!</a> appeared first on <a rel="nofollow" href="https://insum.ca">Insum</a>.</p> Adrian Png https://insum.ca/?p=11954 Fri Jul 13 2018 18:56:08 GMT-0400 (EDT) City of Montreal Recognizes Insum with Intercultural Award https://insum.ca/city-of-montreal-recognizes-insum-intercultural-award/ <h1><span style="color: #8cc63c;">The City of Montreal Recognizes Insum with an Intercultural Award</span></h1> <p>On April 17th, 2018, the City of Montreal honored Insum with the Abe-Limonchik intercultural award.  This distinction recognizes &#8220;exceptional contribution to intercultural relations and the promotion of diversity&#8221;.</p> <p>The evaluation criteria for this unique award are as follows:</p> <ul> <li>The distinct, innovative and exemplary nature of the practices put in place</li> <li>The impact of having created a greater awareness of the richness of ethnocultural diversity</li> <li>The improvement of intercultural relations by bringing together members of various communities and origins.</li> <li>Commitment to the integration of members of diverse origins and their participation in Montreal society</li> <li>The actions aiming to stop discrimination and promote ethnocultural diversity</li> </ul> <p>Furthermore, the award has three categories, which are Individual, Enterprise, and Organization.</p> <p>At the ceremony, the city recognized Insum&#8217;s involvement in several programs encouraging intercultural relations. These commitments lead to the hiring of several highly qualified employees. In addition, Insum makes a point of hiring new immigrants. As a result, they represent 35% of the company&#8217;s workforce.</p> <p>&nbsp;</p> <h2>Insum&#8217;s take on this Intercultural Award</h2> <p>We spoke to Michel St-Amour, President of Insum solutions and to Marie Cadoret, Administrative Assistant, and participant in one of Insum&#8217;s immigration programs.</p> <h2>A President&#8217;s perspective</h2> <p>&#8220;For us, this distinction recognizes our corporate environment or corporate ecosystem, if you will. It nice to know that we stand out in the industry and among our peers, and it also validates what comes naturally to us through our inclusive values. Furthermore, it tells us that there is a quality to what we are doing that you don&#8217;t find elsewhere. It&#8217;s not a cliché to say we accept people as they are, it&#8217;s for real. That&#8217;s because we make no distinctions between countries of origin or religions and we try our best to make everyone feel at home. Everyone has the same importance.</p> <p>So our &#8220;over and above&#8221; effort in this area is recognized for all to see, and that&#8217;s gratifying. Of course, we are looking for people who have a strong desire to integrate into their new communities. But then I would say most people have this desire, anyway. And, when you give them the right conditions, well, they flourish. It is certainly a win-win for all involved.</p> <p>This isn&#8217;t just a characteristic of our Montreal office either. For example, I just got back from our Peruvian office and it has the same culture of acceptance. A significant part of their workforce comes from other  South American countries, and the work dynamic is great. I think this is really good.&#8221;</p> <h2>An administrative assistant&#8217;s perspective</h2> <p>&#8220;I see this as an outside recognition of something that, internally, we knew we already had.  Our internal policies are great in respect of multiculturality. And, both management and employees respect differences. Also, everyone helps sustain this harmonious environment. That&#8217;s especially motivating.  Some companies&#8217; values aren&#8217;t fully accepted by the employees,which of course, doesn&#8217;t work.  We (the employees) actually chose our values.  (ed. Note <a href="http://insum.ca/about-us/">see Insum&#8217;s values here</a>) and there are about 12 nationalities represented here!</p> <h2>The Abe-Limonchik award intercultural award</h2> <p>The Abe-Limonchik Intercultural Award was created in 2009. It is in honor of Abe Limonchik, a former city councilor of the highly diverse Montreal neighborhood of Côte-des-Neiges. Most notably, he worked in the promotion of ethnocultural diversity and the reduction of discrimination.</p> <p>See also: <a href="http://insum.ca/women-in-tech-minority-seeing-positive-change/">Women in Tech</a></p> <p>The post <a rel="nofollow" href="https://insum.ca/city-of-montreal-recognizes-insum-intercultural-award/">City of Montreal Recognizes Insum with Intercultural Award</a> appeared first on <a rel="nofollow" href="https://insum.ca">Insum</a>.</p> Insum Editor https://insum.ca/?p=11135 Fri Jul 13 2018 12:05:15 GMT-0400 (EDT) TypeScript and APEX https://apextips.blogspot.com/2018/07/typescript-and-apex.html TypeScript is a typed superset of JavaScript. That is, you can use the familiar JavaScript syntax you are used to, but where it gets enhanced is the fact it is can be strongly typed to give you compile time warnings.<br /><br />The most example is the sum of two numbers. A typical JavaScript function would looks like:<br /><br /><pre>function add(num1, num2){<br /> return num1 + num2;<br />}<br /></pre><br /><br />By looking at this code, by the function name and the return statement, we can see that the idea would be to add two numbers together. In JavaScript, depending what the user passed in, it could do string concatenation, implicit type casting.<br /><br />So if you do:<br /><br /><pre>add(1,2)</pre><br />This will return 3<br /><br />If you do:<br /><br /><pre>add ("1", 2)</pre><br />This will return 12 (string concatenation).<br /><br />Since we want this function to always add two numbers, using TypeScript, we can change the definition to be:<br /><br /><pre>function add(num1: number, num2: number): number {<br /> return num1 + num2;<br />}<br /></pre><br />Now the TypeScript engine is always going to expect the inputs to be numbers. So in our TypeScript file, if we issue the same statement:<br /><br /><pre>add("1", 2)</pre><br />The compiler is going to complain and you won't be able to transpile into JavaScript code.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-N2PprJu2N_c/W0bH5skKwpI/AAAAAAAAIwQ/UAyZf4fGaNwstwXdAaNrLJp5oQm1umfgACLcBGAs/s1600/Screenshot%2Bfrom%2B2018-07-11%2B23-15-30.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="192" data-original-width="578" height="106" src="https://3.bp.blogspot.com/-N2PprJu2N_c/W0bH5skKwpI/AAAAAAAAIwQ/UAyZf4fGaNwstwXdAaNrLJp5oQm1umfgACLcBGAs/s320/Screenshot%2Bfrom%2B2018-07-11%2B23-15-30.png" width="320" /></a></div><br /><br />What's really neat, a colleague of mine Adrian Png, has gone ahead and created a TypeScript definition of the APEX JavaScript API reference (work in progress). Check out his project on <a href="https://github.com/fuzziebrain/orclapex-js">GitHub</a>. This project provides the documentation to start leveraging that good work that he has done, but for completeness, the basic steps are:<br /><br />1. Ensure your project has been initialized with npm. Run:<br /><br /><pre>npm init</pre><br />..and follow the on screen prompts.<br /><br />2. Install the library to your project folder by using npm:<br /><br /><pre>npm install --save-dev https://github.com/fuzziebrain/orclapex-js.git.</pre><br />What this does is installs the relevant node modules and updates your package json with the relevant dev dependencies.<br /><br />3. Add a tsconfig.json file to your project:<br /><br /><pre>{<br /> "compilerOptions": {<br /> "module": "commonjs",<br /> "lib": [<br /> "es6",<br /> "dom"<br /> ]<br /> }<br />}<br /></pre><br />4. Finally, add the following line to your TypeScript file:<br /><br /><pre>/// &lt;reference types="orclapex-js" /&gt;</pre><pre>&nbsp;</pre>Now, one of the JavaScript API's that has been done is the `apex.da` namespace, which has a function named `resume`. I'm using VSCode, so after adding that reference, there is also some code completion. Typping apex.da.resume give me this hint:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-dFicwphWe00/W0bWCvQA9rI/AAAAAAAAIwc/OjMeNDR6jcUnHLxS3UqqaipfecQZvKzIwCLcBGAs/s1600/Screenshot%2Bfrom%2B2018-07-12%2B00-15-43.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="230" data-original-width="332" height="221" src="https://2.bp.blogspot.com/-dFicwphWe00/W0bWCvQA9rI/AAAAAAAAIwc/OjMeNDR6jcUnHLxS3UqqaipfecQZvKzIwCLcBGAs/s320/Screenshot%2Bfrom%2B2018-07-12%2B00-15-43.png" width="320" /></a></div><br /><br />So not only do we get parameter names, we get to know the expected types. Its worth noting, if you don't add the reference or there is parts of the API that haven't been compiled yet, the TypeScript engine will complain about not knowing about that object.<br /><br />OK, so now with that covered - how can we use TypeScript in our APEX projects.<br /><br />It's not immediately clear from the apex-nitro documentation (credit to Adrian Png for adding TypeScript support into Nitro), but if you navigate into the examples folder you will find a <a href="https://github.com/OraOpenSource/apex-nitro/tree/master/examples/demo-typescript">demo-typescript</a> folder - great, we can leverage apex-nitro to develop TypeScript libraries for our next APEX project. If you don't have apex-nitro installed, install with npm by running: <br /><pre>&nbsp;</pre><pre>npm install apex-nitro -g</pre><pre>&nbsp;</pre>After you install, run apex-nitro config to set up your project. It should end up looking like this:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-zavOdolcHTY/W0bWVkCckAI/AAAAAAAAIwk/5C_l-ydzlXQxJnJPahe8ApEKgqt8yz1TACLcBGAs/s1600/Screenshot%2Bfrom%2B2018-07-12%2B00-17-09.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="903" data-original-width="425" height="320" src="https://3.bp.blogspot.com/-zavOdolcHTY/W0bWVkCckAI/AAAAAAAAIwk/5C_l-ydzlXQxJnJPahe8ApEKgqt8yz1TACLcBGAs/s320/Screenshot%2Bfrom%2B2018-07-12%2B00-17-09.png" width="150" /></a></div><br /><br />They key thing is that the JavaScript processor will be set to be TypeScript. Save that. Now, following the set up guide for apex-nitro for your application, you just need to do a couple of tasks.<br /><br />1. Create a new before header application process with a negative sequence so it's the first thing that runs. Set conditions to owa_util.get_cgi_env('APEX-Nitro') is not null and source to apex_application.g_flow_images := owa_util.get_cgi_env('APEX-Nitro');<br /><br />2. Now, you will want to add a reference to your compiled script. Despite the fact we developed in TypeScript, the output will be JavaScript. So go ahead and somewhere in your application, add the following reference:<br /><br /><pre>#APP_IMAGES#js/app#MIN#.js</pre><br />Now, this was a really quick and dirty example of using apex-nitro. For for full options and usage, you should <a href="https://github.com/OraOpenSource/apex-nitro/blob/master/docs/setup.md">read the docs</a>.<br /><br />Additional resources:<br /><br />TypeScript website: <a href="https://www.typescriptlang.org/">https://www.typescriptlang.org</a><br /><br />There is a good article on FreeCodeCamp that is worth having a read of:&nbsp;<a href="https://medium.freecodecamp.org/when-should-i-use-typescript-311cb5fe801b">https://medium.freecodecamp.org/when-should-i-use-typescript-311cb5fe801b</a> trent tag:blogger.com,1999:blog-8785176694082881912.post-5298345165810158740 Thu Jul 12 2018 13:58:00 GMT-0400 (EDT) Upgrade to SQL Developer 18.2 ? https://svenweller.wordpress.com/2018/07/12/upgrade-to-sql-developer-18-2/ <p><em><strong>Why upgrade to SQL Developer 18?</strong></em></p> <p>This post intents to help you with the decision, if it is about time to upgrade. And if you are on the new version already, then you might find out about some new features that you might not have noticed so far.</p> <p>I recently upgraded from version 17.3 to 18.2.</p> <p>Here is a listing of my favourite changes. This listing includes new features, changed behaviours but also fixed bugs in either version 18.1 or 18.2. It is totally subjective. The focus is on SQL Developer only, I didn&#8217;t analyze changes regarding SQL Data Modeler, sqlcl or ORDS. </p> <p>TL;DR;<br /> Upgrade Now? =&gt; Yes!</p> <h2>Links</h2> <p>If you want you can go through the various documents of new features and bugfixes yourself. </p> <ul> <hr>Oracle SQL Developer</hr> <li><a href="http://www.oracle.com/technetwork/developer-tools/sql-developer/downloads/sqldev-relnotes-181-4423629.html#new" target="_blank">SQL Developer New Features 18.1</a></li> <li><a href="http://www.oracle.com/technetwork/developer-tools/sql-developer/downloads/sqldev-bugsfixed-181-4423628.html" target="_blank">SQL Developer Bugfixes in 18.1</a></li> <li><a href="https://www.oracle.com/technetwork/developer-tools/sql-developer/downloads/sqldev-relnotes182-4958969.html#new" target="_blank">SQL Developer New Features 18.2</a></li> <li><a href="https://www.oracle.com/technetwork/developer-tools/sql-developer/downloads/sqldev-bugsfixed182-4958992.html" target="_blank">SQL Developer Bugfixes in 18.2</a> </li> <hr>SQL command line</hr> <li><a href="http://www.oracle.com/technetwork/developer-tools/sqlcl/downloads/sqlcl-relnotes-181-4428006.html" target="_blank">SQLcl Release Notes 18.1</a></li> <li><a href="http://www.oracle.com/technetwork/developer-tools/sqlcl/downloads/sqlcl-relnotes-182-4959244.html" target="_blank">SQLcl Release Notes 18.2</a></li> <hr>Oracle SQL Data Modeler</hr> <li><a href="http://www.oracle.com/technetwork/developer-tools/datamodeler/downloads/dm-relnotes-181-4423853.html" target="_blank">Data Modeler Release Notes 18.1</a></li> <li><a href="http://www.oracle.com/technetwork/developer-tools/datamodeler/downloads/dm-bugsfixed-181-4423856.html" target="_blank">Data Modeler Bugfixes 18.1</a></li> <li><a href="https://www.oracle.com/technetwork/developer-tools/datamodeler/downloads/dm-relnotes-182-4955084.html?printOnly=1" target="_blank">Data Modeler Release Notes 18.2</a></li> <li><a href="http://www.oracle.com/technetwork/developer-tools/datamodeler/downloads/dm-bugsfixed-182-4955096.html" target="_blank">Data Modeler Bugfixes 18.2</a></li> </ul> <h2>Top new features or bugfixes</h2> <h3>New Welcome Page</h3> <p>It is very likely you disabled the welcome page in a previous version. Go to <em>Help/Start Page</em> to show it. Then you can decide to keep it around by checking the appropriate check box in the lower left corner.</p> <p>In the past this welcome screen was essentially useless. Now it has a section &#8220;RECENT&#8221; connections. It holds the list of the last five recently opend connections which I find myself using a lot.</p> <p>The welcome screen still has a lot that can be improved (in red is what I dislike). But now it is a working and useful part of the tool.<br /> <img data-attachment-id="7825" data-permalink="https://svenweller.wordpress.com/2018/07/12/upgrade-to-sql-developer-18-2/sqldev_182_welcome_screen_b/" data-orig-file="https://svenweller.files.wordpress.com/2018/07/sqldev_182_welcome_screen_b.png?w=809" data-orig-size="947,782" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="sqldev_182_welcome_screen_b" data-image-description="" data-medium-file="https://svenweller.files.wordpress.com/2018/07/sqldev_182_welcome_screen_b.png?w=809?w=300" data-large-file="https://svenweller.files.wordpress.com/2018/07/sqldev_182_welcome_screen_b.png?w=809?w=809" src="https://svenweller.files.wordpress.com/2018/07/sqldev_182_welcome_screen_b.png?w=809" alt="sqldev_182_welcome_screen_b" class="alignnone size-full wp-image-7825" srcset="https://svenweller.files.wordpress.com/2018/07/sqldev_182_welcome_screen_b.png?w=809 809w, https://svenweller.files.wordpress.com/2018/07/sqldev_182_welcome_screen_b.png?w=150 150w, https://svenweller.files.wordpress.com/2018/07/sqldev_182_welcome_screen_b.png?w=300 300w, https://svenweller.files.wordpress.com/2018/07/sqldev_182_welcome_screen_b.png?w=768 768w, https://svenweller.files.wordpress.com/2018/07/sqldev_182_welcome_screen_b.png 947w" sizes="(max-width: 809px) 100vw, 809px" /></p> <p>Also interesting is the DEMO tab in the &#8220;Getting Started&#8221; section. Among others it links to videos about &#8220;Debugging PLSQL&#8221;, &#8220;Importing Data from Excel&#8221; and &#8220;Introduction to Oracle SQLcl&#8221;. </p> <h3>Improved Editor / Syntax Highlighting</h3> <p>Syntax Highlighting is arguably one of the most crucial features of any IDE.<br /> A lot of bugfixes have been done for that.<br /> Here is a quick list of changes/bugfixes with regards to the editor or syntax highlighting. The list is not complete.</p> <ul> <li>Improved Arbori Editor: <ul> <li>syntax error highlighting</li> <li>catch syntax errors before Arbori execution</li> </ul> </li> <li>Change Case as You Type was removed from the Code Insight Preferences page. Use the Code Formatter to set your identifier and keyword preferences, and format your code on demand instead. </li> <li>SQL Injection vulnerability warnings for your PL/SQL</li> <li>27678178 PARSER DOESN’T LIKE NEW FOR CALLING A USERDEFINED CONSTRUCTOR IN A SQLBLOCK</li> <li>27718434 FORUM: SOME KEYWORDS ARE HIGHLIGHTED ONLY WHILE TYPING</li> <li>27803006 FORUM: BRACES () COLORING IS INTERMITTENT AND DIFFERENT FROM PREFERENCES</li> <li>27939025 FORUMS: BETTER PL/SQL SYNTAX HIGHLIGHTING/FORMATTER FOR CONDITIONAL COMPILATION SYNTAX</li> </ul> <p>Since I use conditional compiling a lot in PLSQL the last fix is an essential one for me. </p> <p>SQL Injection detection is a very promising feature. Especially when working with not so experienced developers. They easily might overlook some SQL injection issue and now the editor is able to warn about such scenarios. Jeff explains more about it <a href="https://www.thatjeffsmith.com/archive/2018/04/18-1-features-sql-injection-detection/" target="_blank">here</a>.</p> <p>Btw: &#8220;Arbori&#8221; refers to the language used to describe parse trees during syntax analysis. <a href="https://vadimtropashko.files.wordpress.com/2017/02/arbori2.pdf" target="_blank">Want to know more</a>? </p> <h3>DBA Users Editor – SQL page now generates complete DDL for user including GRANTS</h3> <p>Way overdue. Happens a lot that you want a script to create the same schema that you have in some DEV environment and now you want to script the user creation for TEST and potentially PROD environments. </p> <p>In the past the grants had been missing. A quick test of mine showed that all the grants that this schema needs seem to be there now. Granted roles, object privs, granted access to directory objects, granted system privileges. However <strong>grants that are given to other users are not included</strong>! So it is still not complete.</p> <p>And remember, there also is a &#8220;create like&#8221; feature in the DBA panel. </p> <p><img data-attachment-id="7827" data-permalink="https://svenweller.wordpress.com/2018/07/12/upgrade-to-sql-developer-18-2/sqldev_182_create_like/" data-orig-file="https://svenweller.files.wordpress.com/2018/07/sqldev_182_create_like.png?w=809" data-orig-size="394,362" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="sqldev_182_create_like" data-image-description="" data-medium-file="https://svenweller.files.wordpress.com/2018/07/sqldev_182_create_like.png?w=809?w=300" data-large-file="https://svenweller.files.wordpress.com/2018/07/sqldev_182_create_like.png?w=809?w=394" src="https://svenweller.files.wordpress.com/2018/07/sqldev_182_create_like.png?w=809" alt="sqldev_182_create_like" class="alignnone size-full wp-image-7827" srcset="https://svenweller.files.wordpress.com/2018/07/sqldev_182_create_like.png 394w, https://svenweller.files.wordpress.com/2018/07/sqldev_182_create_like.png?w=150 150w, https://svenweller.files.wordpress.com/2018/07/sqldev_182_create_like.png?w=300 300w" sizes="(max-width: 394px) 100vw, 394px" /></p> <p>This &#8220;create like&#8221; has <strong>not</strong> all the grants that are on the DBA Users Editor SQL Page.</p> <h3>27169586 ALTER SCRIPT SCROLLS OFF PAGE, IMPOSSIBLE TO READ WITHOUT MUCH SCROLLING/RESIZE</h3> <p>I&#8217;m not sure, but I think I hit this bug very often in the past. And then it was annoying as hell. However we can&#8217;t access the bug numbers, so I&#8217;m not sure if that fix covers the problematic behaviour that I remember. At least it looks as if it is fixed now. Will monitor it closely.</p> <h3>Improved Code Formatter</h3> <p>I&#8217;m not a big fan of code formatters. But I know those matters to many developers. The bugfix lists are full of minor changes to it.</p> <p>Two things I would like to point out:</p> <ul> <li>Formatter: New Basic Preference: Convert Case Only <p>This new setting means, the code will not be reorganized. Only the UPPER/lower case logic is applied. I personally like to have everything in lowercase (apart from some plsql method names where I use lowerCamelCase). So this setting allows me to quickly format SQL statements in the worksheet.<br /> <img data-attachment-id="7830" data-permalink="https://svenweller.wordpress.com/2018/07/12/upgrade-to-sql-developer-18-2/sqldev_182_format_case_only/" data-orig-file="https://svenweller.files.wordpress.com/2018/07/sqldev_182_format_case_only.png?w=809" data-orig-size="995,569" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="sqldev_182_format_case_only" data-image-description="" data-medium-file="https://svenweller.files.wordpress.com/2018/07/sqldev_182_format_case_only.png?w=809?w=300" data-large-file="https://svenweller.files.wordpress.com/2018/07/sqldev_182_format_case_only.png?w=809?w=809" src="https://svenweller.files.wordpress.com/2018/07/sqldev_182_format_case_only.png?w=809" alt="sqldev_182_format_case_only" class="alignnone size-full wp-image-7830" srcset="https://svenweller.files.wordpress.com/2018/07/sqldev_182_format_case_only.png?w=809 809w, https://svenweller.files.wordpress.com/2018/07/sqldev_182_format_case_only.png?w=150 150w, https://svenweller.files.wordpress.com/2018/07/sqldev_182_format_case_only.png?w=300 300w, https://svenweller.files.wordpress.com/2018/07/sqldev_182_format_case_only.png?w=768 768w, https://svenweller.files.wordpress.com/2018/07/sqldev_182_format_case_only.png 995w" sizes="(max-width: 809px) 100vw, 809px" /></p> </li> <li>FORUM &#8211; ADDED FORMATTER OPTION: RIGHT-ALIGN QUERY KEYWORDS <p>I know that many developers like to format their SQL queries in such a way, that the keywords are right alined. So this is possible now.</p> <p><img data-attachment-id="7833" data-permalink="https://svenweller.wordpress.com/2018/07/12/upgrade-to-sql-developer-18-2/sqldev_182_formatter_right_align/" data-orig-file="https://svenweller.files.wordpress.com/2018/07/sqldev_182_formatter_right_align.png?w=809" data-orig-size="993,568" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="sqldev_182_formatter_right_align" data-image-description="" data-medium-file="https://svenweller.files.wordpress.com/2018/07/sqldev_182_formatter_right_align.png?w=809?w=300" data-large-file="https://svenweller.files.wordpress.com/2018/07/sqldev_182_formatter_right_align.png?w=809?w=809" src="https://svenweller.files.wordpress.com/2018/07/sqldev_182_formatter_right_align.png?w=809" alt="sqldev_182_formatter_right_align" class="alignnone size-full wp-image-7833" srcset="https://svenweller.files.wordpress.com/2018/07/sqldev_182_formatter_right_align.png?w=809 809w, https://svenweller.files.wordpress.com/2018/07/sqldev_182_formatter_right_align.png?w=150 150w, https://svenweller.files.wordpress.com/2018/07/sqldev_182_formatter_right_align.png?w=300 300w, https://svenweller.files.wordpress.com/2018/07/sqldev_182_formatter_right_align.png?w=768 768w, https://svenweller.files.wordpress.com/2018/07/sqldev_182_formatter_right_align.png 993w" sizes="(max-width: 809px) 100vw, 809px" /><br /> <em>Example Result</em></p> <pre class="brush: sql; title: ; notranslate"> -- left alined keywords select containerid ,status ,reason ,additional_info from table1 t1 left join table2 t2 on t1.id = t2.id where barcode = :barcode; </pre> <pre class="brush: sql; title: ; notranslate"> -- right alined keywords select containerid ,status ,reason ,additional_info from table1 t1 left join table2 t2 on t1.id = t2.id where barcode = :barcode; </pre> </li> </ul> <h2>Interesting new features or bugfixes</h2> <p>The following features are less deciding. So they might not be the sole reason why you want to upgrade. However they might be useful to know and to try out eventually.</p> <ul> <li>Can now convert Oracle to ANSI Joins with context menu <p>This feature sounds very promising. Unfortunatly I didn&#8217;t find the context menu yet, that allows to do so. So far I tried it only on a 11.2.0.4 db. Maybe the option uses functionality that requires a higher db version. </li> <li>DBMS_XPLAN Added to Explain Drop Down toolbar menus<br /> <img data-attachment-id="7831" data-permalink="https://svenweller.wordpress.com/2018/07/12/upgrade-to-sql-developer-18-2/sqldev_182_dbms_xplan/" data-orig-file="https://svenweller.files.wordpress.com/2018/07/sqldev_182_dbms_xplan.png?w=809" data-orig-size="526,633" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="sqldev_182_DBMS_XPLAN" data-image-description="" data-medium-file="https://svenweller.files.wordpress.com/2018/07/sqldev_182_dbms_xplan.png?w=809?w=249" data-large-file="https://svenweller.files.wordpress.com/2018/07/sqldev_182_dbms_xplan.png?w=809?w=526" src="https://svenweller.files.wordpress.com/2018/07/sqldev_182_dbms_xplan.png?w=809" alt="sqldev_182_DBMS_XPLAN" class="alignnone size-full wp-image-7831" srcset="https://svenweller.files.wordpress.com/2018/07/sqldev_182_dbms_xplan.png 526w, https://svenweller.files.wordpress.com/2018/07/sqldev_182_dbms_xplan.png?w=125 125w, https://svenweller.files.wordpress.com/2018/07/sqldev_182_dbms_xplan.png?w=249 249w" sizes="(max-width: 526px) 100vw, 526px" /><br /> The new option does not create a plan immediatly. Instead it finds the sql_id and then produces a statement that uses the sql_id and then can read the execution plan using DBMS_XPLAN.</p> <pre class="brush: sql; light: true; title: ; notranslate"> select * from table(dbms_xplan.display_cursor( sql_id=&gt;'d7yr3jw0rj963', format=&gt;'ALLSTATS LAST')); </pre> </li> <p>DBMS_XPLAN is the best way to get a nicely formatted execution plan.</p> <li>Enhanced DB Search for dependencies and selected object types <p>It is not clear what was enhanced. The search menu certainly looks the same. Also the search findings didn&#8217;t really seem to change. </p> <p>In case you don&#8217;t know, but search does cover view sources. This was already implemented a few versions ago.</p> <p>I use the DB Search a lot. And I welcome any improvements in that area, even if I don&#8217;t see them at first glance.</p> </li> <li>ORDS 18.2 bundled <p><em>Tools/REST Data Services </em></p> <p><img data-attachment-id="7832" data-permalink="https://svenweller.wordpress.com/2018/07/12/upgrade-to-sql-developer-18-2/sqldev_182_ords_version/" data-orig-file="https://svenweller.files.wordpress.com/2018/07/sqldev_182_ords_version.png?w=809" data-orig-size="645,479" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="sqldev_182_ords_version" data-image-description="" data-medium-file="https://svenweller.files.wordpress.com/2018/07/sqldev_182_ords_version.png?w=809?w=300" data-large-file="https://svenweller.files.wordpress.com/2018/07/sqldev_182_ords_version.png?w=809?w=645" src="https://svenweller.files.wordpress.com/2018/07/sqldev_182_ords_version.png?w=809" alt="sqldev_182_ords_version" class="alignnone size-full wp-image-7832" srcset="https://svenweller.files.wordpress.com/2018/07/sqldev_182_ords_version.png 645w, https://svenweller.files.wordpress.com/2018/07/sqldev_182_ords_version.png?w=150 150w, https://svenweller.files.wordpress.com/2018/07/sqldev_182_ords_version.png?w=300 300w" sizes="(max-width: 645px) 100vw, 645px" /> </li> <li>Extract variable/function prototype <p>Refactoring code is something that SQL Developer supports since many versions now. It is surprising that almost no developers know about it or even use that frequently.</p> <p>This new option allows to quickly change expressions into local functions. This can save an aweful lot of codeing time!</p> <p><em>Example</em></p> <p>Somewhere inside my plsql code I have a concatenation.</p> <pre class="brush: sql; highlight: [5]; title: ; notranslate"> ... begin ... if v_json is not null then p_plate.additional_info := '{'||v_json||'}'; end if; ... </pre> <p>I mark the <code>'{'||v_json||'}'</code> part, open the right context menu, choose <em>Refactoring / Extract Variable/Function/CTE</em> and give the function a new name, for example <em>make_json_object</em>.</p> <p><img data-attachment-id="7834" data-permalink="https://svenweller.wordpress.com/2018/07/12/upgrade-to-sql-developer-18-2/sqldev_182_refactor_expression/" data-orig-file="https://svenweller.files.wordpress.com/2018/07/sqldev_182_refactor_expression.png?w=809" data-orig-size="877,568" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="sqldev_182_refactor_expression" data-image-description="" data-medium-file="https://svenweller.files.wordpress.com/2018/07/sqldev_182_refactor_expression.png?w=809?w=300" data-large-file="https://svenweller.files.wordpress.com/2018/07/sqldev_182_refactor_expression.png?w=809?w=809" src="https://svenweller.files.wordpress.com/2018/07/sqldev_182_refactor_expression.png?w=809" alt="sqldev_182_refactor_expression" class="alignnone size-full wp-image-7834" srcset="https://svenweller.files.wordpress.com/2018/07/sqldev_182_refactor_expression.png?w=809 809w, https://svenweller.files.wordpress.com/2018/07/sqldev_182_refactor_expression.png?w=150 150w, https://svenweller.files.wordpress.com/2018/07/sqldev_182_refactor_expression.png?w=300 300w, https://svenweller.files.wordpress.com/2018/07/sqldev_182_refactor_expression.png?w=768 768w, https://svenweller.files.wordpress.com/2018/07/sqldev_182_refactor_expression.png 877w" sizes="(max-width: 809px) 100vw, 809px" /></p> <p>The result is that my procedure got a local function. And the marked expression is replaced with a call to that function.</p> <pre class="brush: sql; highlight: [10]; title: ; notranslate"> ... --refactored function function make_json_object(v_json clob) return varchar2 is begin return '{'||v_json||'}'; end make_json_object; begin ... if v_json is not null then p_plate.additional_info := make_json_object(v_json); end if; ... </pre> <p>The code would still require some rework, but it is a nice quick starting point.<br /> As always you can undo that change using CTRL-Z.</p> </li> <li>Allow explain/autotrace on selected text <p>This I like a lot. You can mark a part of a bigger sql statement and get the explain plan for that part only. The marked code needs to be a valid SQL statement of cause.</p> <p>Highly useful for with clause statements. But also for expanded SQL queries. </li> <li>27962558 DRAG AND DROP FROM GRID TO EDITOR SHOULD QUOTE STRINGS <p>The behaviour for drag and drop changed. I&#8217;m not so convinced about it, but I rarely use drag and drop from the grid. </p> <p>If we drag from a <em>single</em> varchar2 column, then all the values are copied, put in single quotes and separated by comma.<br /> However if we copy from <em>multiple </em>columns then the strings are not quoted.<br /> The quoteing only happens during drag and drop. Not when copying with CTRL+C, CTRL+V.</p> <p>I think this feature can be highly helpful, but needs some getting used to it. </li> </ul> <h2>Conclusion</h2> <p>There are several more changes, but those are the ones I am most interested in. As with any new toy we should check what is possible and how we can use it to improve our <del datetime="2018-07-12T15:49:28+02:00">playing</del> codeing experience.</p> <p>Several of the new features are so convincing to me that I installed SQL Developer 18.2 now in all projects that I supervise.</p> <p>Feel free to share what new features or bugfixes you like most!</p> svenweller http://svenweller.wordpress.com/?p=7823 Thu Jul 12 2018 10:06:35 GMT-0400 (EDT) Cross Row Interactive Grid Cascading LOVs http://www.explorer.uk.com/cross-row-interactive-grid-cascading-lovs/ <p>One of my main gripes about the Interactive Grid is that it performing cross row validations is quite a painful process. By this I mean, the user can modify various records and add their own; but I want to check if the entries are valid in relation to each other before submitting to the DB. For example: upon completing user edits, I want to <a href="https://apex.oracle.com/pls/apex/f?p=118853" target="_blank" rel="noopener">check if at least one Admin exists</a>, or check if all entered values add up to 100, or check if there are an equal amount of records of each type been entered, or check if there are no duplicated records… that kind of thing.</p> <p>The challenges comes when you need to cascade an LOV across records:  A select list showing a custom set of records based on other rows in the grid. The problem is that the select list is based on a SQL statement and just cannot be based on the Interactive Grid Model (which holds the modified record values) or indeed the IG column value – even with the PLSQL bind syntax.</p> <p>One trick I have used here to create a hidden item and then use an on change event to populate that item and then refresh the select list – however you have to reset that hidden item when clicking through records (apexendrecordedit or interactivegridselectionchange should do it) and it can be tricky.</p> <p>How do I do it? Let’s take the “check there are no duplicated records scenario” from my example list above. I want to prevent the entry of duplicate records by disallowing them to enter duplicates in the first place rather than validate on save (more on this later). In my example I want them to enter Regions (e.g. Europe, Americas, etc.) and Notes – but they can’t add more than one Region of the same name to the Grid. <a href="https://apex.oracle.com/pls/apex/f?p=116686:" target="_blank" rel="noopener">You can follow the example here and see my code</a>.</p> <p>So the way I do it is to create the grid as normal – my columns are</p> <ul> <li>REGION_ID column is a select list based on a query</li> <li>NOTES column is a text item</li> </ul> <pre class="brush: php; title: ; notranslate"> SELECT region_name d, region_id r FROM regions ORDER BY region_name </pre> <p>…standard stuff so far.</p> <p><a href="http://www.explorer.uk.com/wp-content/uploads/2018/07/Region-Select-List-Oracle-APEX.png" rel="lightbox[7384] attachment wp-att-7388"><img class="aligncenter wp-image-7388 size-medium" src="http://www.explorer.uk.com/wp-content/uploads/2018/07/Region-Select-List-Oracle-APEX-266x300.png" alt="" width="266" height="300" srcset="http://www.explorer.uk.com/wp-content/uploads/2018/07/Region-Select-List-Oracle-APEX-266x300.png 266w, http://www.explorer.uk.com/wp-content/uploads/2018/07/Region-Select-List-Oracle-APEX.png 348w" sizes="(max-width: 266px) 100vw, 266px" /></a></p> <p>I have also created a new Select List Page Item on the page called P1_REGION_SELECT_LIST which is based on the following “PL/SQL Function Body returning SQL”</p> <pre class="brush: php; title: ; notranslate"> DECLARE lv_lov_source APEX_APPL_PAGE_IG_COLUMNS.&lt;em&gt;LOV_SOURCE&lt;/em&gt;%TYPE; BEGIN SELECT LOV_SOURCE INTO lv_lov_source FROM APEX_APPL_PAGE_IG_COLUMNS WHERE application_id = :APP_ID AND page_id = :APP_PAGE_ID AND name ='REGION_ID'; RETURN lv_lov_source; END; </pre> <p>I’m going to use this item as my <em>template item</em> – i.e. this item contains all the possible options. Rather than repeat the same SQL from the REGION_ID item, I’m going to <em>reuse</em> it by pulling the same SQL out from the meta-data from the REGION_ID IG Column. This way, if the item SQL requires a change&#8230; I just change it in one place. Also since I do not want to show this item to my users, I will add some CSS to hide it (I could’ve used a dynamic action – but it’s faster this way).</p> <p>The idea is, when the user clicks a row in edit mode, a Dynamic Action on Row Initialisation fires which resets the select list entries within the IG column.</p> <p>So in pseudocode, when I initialise my IG Row…</p> <ol> <li>I remove all select list entries from my REGION_ID IG select list column</li> <li>I set my REGION_ID IG select list column to have exactly the same entries from the template item P1_REGION_SELECT_LIST</li> <li>Then I loop around the modal and remove any entries that already exist as non-deleted records.</li> <li>If I get to the row I’m on; well I’ve just wiped out all the select list entries so I need to set the selected value back to the one held in the modal.</li> </ol> <p>I have to do this for every click of a different record. This is because the select list REGION_ID is static for all rows; if I change the select list entries once, it the same changed-state for all record. That is why I have to destroy &amp; rebuild the list every time. The good thing is that the model just holds values – so once the value is changed, regardless of how many entries are in the select list, it persists in the model.</p> <p>You can see a working example, together with code examples here:<br /> <a href="https://apex.oracle.com/pls/apex/f?p=116686" target="_blank" rel="noopener">https://apex.oracle.com/pls/apex/f?p=116686</a></p> <p>The deleted records cause <u>great</u> problems. Why? Because it’s possible the user can delete an entry, then add a duplicate non-deleted one, then Refresh Rows of the deleted record and press save… causing a duplicate. Furthermore, Duplicating Records and adding New Rows when the IG is at capacity requires custom built solutions.</p> <p>Rather than explain the ins and outs of duplication preventing client side; here are a few things to consider.</p> <ol> <li>Add a server side validation to prevent duplicates</li> <li>At the very least a unique index protecting your table</li> <li>Use a PL/SQL based DML process with duplicate detection</li> <li>Add a before-submit dynamic action to check the modal for duplicates</li> <li>Use the Save “button swap” technique, combined with a model check (see above)</li> <li>Remove IG actions like duplicate from the IG in the advanced JS configuration area to reduce chances of duplicate creation (I have used this in my demo application)</li> <li>Consider how the Add Button can be enabled/disabled to prevent new rows been added when the grid is at capacity (i.e. when the maximum number of distinct rows can be added)</li> </ol> <p>As explained earlier; this is my gripe that cross model validations are not out-of-the-box, that I can’t easily compare user entered/modified records and I have to plumb all the routes that the user has available to them to cause problems. It would be really great if this sort of thing was available out of the box.</p> <p>The post <a rel="nofollow" href="http://www.explorer.uk.com/cross-row-interactive-grid-cascading-lovs/">Cross Row Interactive Grid Cascading LOVs</a> appeared first on <a rel="nofollow" href="http://www.explorer.uk.com">Explorer | Award Winning UK Oracle Partner</a>.</p> Matt Mulvaney http://www.explorer.uk.com/?p=7384 Thu Jul 12 2018 07:45:16 GMT-0400 (EDT) Nombres de Columnas en Tablas - Mantener Mayúsculas/Minúsculas o no? http://feedproxy.google.com/~r/DescubriendoElMundoDeOracle/~3/Z2s8Y7lf0qE/nombres-de-columnas-en-tablas-mantener.html Hola en esta oportunidad solo quiero compartir contigo algunas experiencias que he tenido con el uso de nombres de columnas de tipo formato título, es decir manteniendo las mayúsculas y mínúsculas.<br /><br />Para ponernos en contexto, supongamos que creamos una tabla en el Taller de SQL de la siguiente forma:<br /><br />Tabla Nombre: CMO_CUSTOMER<br />Columnas:<br />- Cust_ID<br />- Cust_FirstName<br />- Cust_LastName<br /><br />Y seleccionamos el checkbook <b>Mantener Mayúsculas/Minúsculas</b><br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-nzmeBTDggoU/W0ZDXXCTCyI/AAAAAAAAMCk/bugEDzSWbegjeK6Nh1kbV2X0WSfm6bJcACLcBGAs/s1600/img1.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="947" data-original-width="1508" height="250" src="https://4.bp.blogspot.com/-nzmeBTDggoU/W0ZDXXCTCyI/AAAAAAAAMCk/bugEDzSWbegjeK6Nh1kbV2X0WSfm6bJcACLcBGAs/s400/img1.JPG" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">Al finalizar el asistente tenemos creada la tabla con los nombres de columnas de esta forma:</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-dR-KvimtJWo/W0ZCDzvZLUI/AAAAAAAAMCY/bBhbnMyu-t06rsGJaj24s52MMjs_dSUAACLcBGAs/s1600/img2.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="414" data-original-width="914" height="180" src="https://1.bp.blogspot.com/-dR-KvimtJWo/W0ZCDzvZLUI/AAAAAAAAMCY/bBhbnMyu-t06rsGJaj24s52MMjs_dSUAACLcBGAs/s400/img2.JPG" width="400" />&nbsp;</a></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Que inconvenientes me trajo el usar "<b>Mantener Mayúsculas/Minúsculas</b>"<b> </b>en Apex?<b><br /></b></div><div class="separator" style="clear: both; text-align: left;"></div><a name='more'></a><br /><br /><div class="separator" style="clear: both; text-align: left;">En primer lugar cuando creamos una consulta SQL en nuestra aplicación y queremos mostrar ciertas columnas de la tabla, es necesario encerrar cada nombre de columna entre comillas dobles.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">select "Cust_FirstName", "Cust_LastName"<br />from cmo_customer</span></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Si no lo encerramos entre comillas nos&nbsp; muestra el error: <b>Invalid indentifier</b></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-MYk_LE13btI/W0ZGAdIdzBI/AAAAAAAAMC4/eT9loz6WFbM0P9MfgXulzFqirsRFLG7mgCLcBGAs/s1600/img4.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="488" data-original-width="1372" height="141" src="https://2.bp.blogspot.com/-MYk_LE13btI/W0ZGAdIdzBI/AAAAAAAAMC4/eT9loz6WFbM0P9MfgXulzFqirsRFLG7mgCLcBGAs/s400/img4.JPG" width="400" /></a></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Entonces siempre debemos recordar de colocar las comillas dobles.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Eso no pasa si creamos la tabla con las columnas sin especificar el checkbox&nbsp; <b>Mantener Mayúsculas/Minúsculas. </b>Ya que las columnas se van a crear todo en mayúsculas en la tabla, no importando si lo escribimos en formato minúscula y mayúscula.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-TJz9FHFR5ek/W0ZD8QXu9xI/AAAAAAAAMCs/HWZIe74TUo8hFU3EgGXDOWflb5qO1eW-ACLcBGAs/s1600/img3.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="410" data-original-width="906" height="180" src="https://3.bp.blogspot.com/-TJz9FHFR5ek/W0ZD8QXu9xI/AAAAAAAAMCs/HWZIe74TUo8hFU3EgGXDOWflb5qO1eW-ACLcBGAs/s400/img3.JPG" width="400" /></a></div><div class="separator" style="clear: both; text-align: left;"></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Otro problema es a la hora de querer filtrar un reporte por medio de la URL.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Supongamos que tenemos un botón el cual filtra nuestro reporte pasando el parámetro por la URL.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">A modo de ejemplo he creado un botón en una página y la acción es <b>Redirigir a URL</b>:</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">http://localhost:8080/apex/f?p=&amp;APP_ID.:2:&amp;SESSION.::NO:RP,2,CIR:IR[IDENTIFICADOR_ESTATICO_REGION_INFORME_INTERACTIVO]</span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">_&lt;NOMBRE_COLUMNA&gt;:&lt;VALOR&gt;&nbsp; </span></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">http://localhost:8080/apex/f?p=&amp;APP_ID.:2:&amp;SESSION.::NO:RP,2,CIR:IR[CUST]_Cust_ID:4&nbsp;</span></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Mi region del reporte interactivo de la página 2 tiene un identificador estático denominado <b>CUST</b>.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Por mas que pasamos el nombre de columna y su valor el informe interactivo no se filtrará:</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-JdUKp-aa5LI/W0ZPqs5pT5I/AAAAAAAAMDI/Y4u8ZfMuvvgji5St1wirhVuO-F6THGl1QCLcBGAs/s1600/img5.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="618" data-original-width="1350" height="182" src="https://2.bp.blogspot.com/-JdUKp-aa5LI/W0ZPqs5pT5I/AAAAAAAAMDI/Y4u8ZfMuvvgji5St1wirhVuO-F6THGl1QCLcBGAs/s400/img5.JPG" width="400" /></a></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">&nbsp;Lo que necesitamos hacer es colocar un alias de columna en la consulta SQL del Informe Interactivo</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">select "Cust_ID" <b>"CUST_ID"</b>, <br />"Cust_FirstName",<br />"Cust_LastName"<br />from CMO_CUSTOMER</span></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-OmLr4ORO-U8/W0ZQioPbRMI/AAAAAAAAMDQ/EJfZSjpkgAQxcztmV_ZBZGxEpWzj0OMowCLcBGAs/s1600/img6.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="477" data-original-width="1102" height="172" src="https://3.bp.blogspot.com/-OmLr4ORO-U8/W0ZQioPbRMI/AAAAAAAAMDQ/EJfZSjpkgAQxcztmV_ZBZGxEpWzj0OMowCLcBGAs/s400/img6.JPG" width="400" /></a></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"></div>De esa forma se filtra el reporte sin problemas.<br /><b><br /></b>En el caso que usemos las columnas de la tabla sin especificar<b> </b><b>Mantener Mayúsculas/Minúsculas, </b>no tendríamos ese problema de tener que colocar un alias de columnas si no quisieramos.<br /><b><br /></b>Cuando se crea el reporte por medio del asistente, éste coloca las comillas dobles a cada columna:<br /><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">select "CUST_ID", <br />"CUST_FIRSTNAME",<br />"CUST_LASTNAME"<br />from CMO_CUSTOMER</span><br />&nbsp; <br />Pero si nosotros ingresamos la consulta SQL manualmente, de igual forma funcionaría el filtro del reporte sin ningún problema. <br /><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">select cust_id, cust_firstname,cust_lastname <br />from cmo_customer</span><br /><br /><b></b><br />Pasando esta URL en el botón:<br /><br /><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">http://localhost:8080/apex/f?p=&amp;APP_ID.:2:&amp;SESSION.::NO:RP,2,CIR:IR[CUST]_<b>Cust_ID</b>:4&nbsp;</span><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;"><br /></span><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;"></span><span style="font-family: inherit;">o esta:&nbsp;</span><br /><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;"><br /></span><span style="font-family: &quot;courier new&quot; , &quot;courier&quot; , monospace;">http://localhost:8080/apex/f?p=&amp;APP_ID.:2:&amp;SESSION.::NO:RP,2,CIR:IR[CUST]_<b>CUST_ID</b>:4</span><br /><b><br /></b>En conclusión a mi me gusta mas trabajar con los nombres de columna en mayúsuclas, que especificar si es mayúsculas o minúsculas.<br /><br />Te dejo a ti que decidas la forma que más te gustaría trabajar en esta situación.<br /><b><br /></b><img src="http://feeds.feedburner.com/~r/DescubriendoElMundoDeOracle/~4/Z2s8Y7lf0qE" height="1" width="1" alt=""/> Clarisa J. Maman Orfali tag:blogger.com,1999:blog-1315583943401206186.post-3902134979413877485 Wed Jul 11 2018 15:06:00 GMT-0400 (EDT) I’ve moved! https://ruepprich.wordpress.com/2018/07/11/ive-moved/ <h1>Please come by my new site at <a href="https://ruepprich.com/">ruepprich.com</a>.</h1> Christoph Ruepprich http://ruepprich.wordpress.com/?p=2914 Wed Jul 11 2018 11:34:08 GMT-0400 (EDT) Oracle Forms Migration http://www.grassroots-oracle.com/2018/07/oracle-forms-migration-to-APEX.html This post is one of a <a href="http://www.grassroots-oracle.com/2018/06/things-i-learned-while-not-at-kscope18.html" target="_blank">series</a> on what I learned while <i>not </i>at Kscope18.<br /><br />I realise that's a month ago now, but the mind still ponders, and I've had these lined up for a while. Just got busy with a deployment, as you do. Went nice and smooth though, APEX sure does make staggered deployments easier with build options. <a href="http://www.grassroots-oracle.com/search/label/Build%20Options" target="_blank">Underrated feature</a>. /tangent<br /><br />Anyhoo - every <a href="https://community.oracle.com/message/14848339" target="_blank">now</a> <a href="https://community.oracle.com/message/14168364" target="_blank">and</a> <a href="https://community.oracle.com/message/13937571" target="_blank">then</a> someone on the forum asks about the Oracle Forms migration tool. I've noticed it a bit recently, I guess that's a good thing.<br /><br /><blockquote class="twitter-tweet" data-lang="en"><div dir="ltr" lang="en">From <a href="https://twitter.com/orcl_dpeake?ref_src=twsrc%5Etfw">@orcl_dpeake</a> presentation. I think there is a step „do some magic“ missing. <a href="https://t.co/h4Bgyy2fm5">pic.twitter.com/h4Bgyy2fm5</a></div>— PeterRaganitsch (@PeterRaganitsch) <a href="https://twitter.com/PeterRaganitsch/status/1006992606340026368?ref_src=twsrc%5Etfw">June 13, 2018</a></blockquote><br />Oracle Forms Migration. I guess what I'm learning here is that sometimes I'm a little shocked they keep at it, but I guess you've got to play the odds. And I haven't heard what was said with this slide.<br /><br />I'd like to start and alternate list:<br /><br />1) Setup <b>APEX. </b>Of course. <a href="http://www.grassroots-oracle.com/2018/06/oracle-xe-18c-and-oraclerad.html" target="_blank">OracleRAD</a>&nbsp;will make this a breeze.<br /><br />2) Create a <b>schema </b>that will serve as your conduit to your existing data. Privileges become additive, adding another layer to protect your data, which may include information not for the relevant APEX application.<br /><br />3) <b>Analyse </b>what needs to change, what's broken, what's required.<br /><i><br /></i><i>Important note </i>- workflow in a browser&nbsp;<b>will </b>be different from Oracle Forms.<br /><br />While the components, capabilities, and IDE are astonishingly similar, I would never bother converting Form-&gt;Page. You'll spend more time cleaning when you could be doing more productive building.<br /><div><br /></div>The web universe just works different to Forms. It offers different opportunities. For instance, it's easier to build walk-through wizards for data entry. This can be important in touch device world, offering interaction with buttons instead of virtual keyboard is a plus.<br /><br />Our applications now tend to generally require less keystrokes for <i>information </i>to be&nbsp;added, it's more of an interaction of buttons.<br /><br />4) <b>Import </b>your Forms code if you must, but only for the ability to annotate existing code while you build the fresh interface. You may get better mileage by analysing straight from Oracle Forms.<br /><br />The spectrum of code you'll need to ditch/refactor/keep will vary depending on the quality of the legacy application.<br /><br />Continue analysis of business rules. Are they fully known? stale? Does workflow need improvement? Maybe concessions were made during the Forms development.<br /><br />5) <b>Enhance </b>- not always necessary, but always good to add polish. But this notion of RAD? Yep, you get pretty darn good apps without even trying to add polish. And polish with a few Dynamic Actions go a long way.<br /><br />And with APEX plugins, polish comes in big, free tubs. And yes, you should <a href="https://twitter.com/swesley_perth/status/1010700067399860224" target="_blank">embrace plugins</a>.<br /><br />6) <b>Test</b>. Of course. And with clicky people. People who click about for the sake of clicking stuff. They're the people that are going to find those left field holes.<br /><br />7) <b>Train</b>. While you can never replace face-to-face explanations, hopefully your application will explain itself.<br /><br />8) <b>Rollout</b>, and enjoy applications that aren't easily obstructed as new versions of APEX arrive.<br />Applications that <a href="https://twitter.com/joelkallman/status/1013966383846248448" target="_blank">run fast</a>, derived directly from business data, data delivered to the right people, with a <a href="http://www.grassroots-oracle.com/2018/05/filtering-outliers-from-oracle-apex-workspace-activity-logs.html" target="_blank">natural history</a> of who visited what and how long it took them.<br /><br />We've got a keeper. Scott Wesley tag:blogger.com,1999:blog-4818542164384221282.post-1942543820021825552 Wed Jul 11 2018 08:32:00 GMT-0400 (EDT) ORA-12545 When running Oracle inside Docker https://ruepprich.wordpress.com/2018/07/10/ora-12545-when-running-oracle-inside-docker/ <p>When trying to make an http request from my Oracle database running inside a Docker container, I received the following error:</p> <pre class="">SQL&gt; select utl_http.request('http://api.open-notify.org/iss-now.json') from dual; Error starting at line : 1 in command - select utl_http.request('http://api.open-notify.org/iss-now.json') from dual Error report - ORA-29273: HTTP request failed ORA-06512: at "SYS.UTL_HTTP", line 1722 ORA-12545: Connect failed because target host or object does not exist ORA-06512: at line 1</pre> <p>This puzzled me quite a bit. The error pretty much says that it cannot resolve the hostname <em>api.open-notify.org</em>. When I run a simple curl command from my host, I get the expected result.</p> <pre class="">$ curl http://api.open-notify.org/iss-now.json {"message": "success", "iss_position": {"longitude": "-144.6590", "latitude": "-36.9405"}, "timestamp": 1531175688}[oracle@jcat-server sh]</pre> <p>Then it dawned on me to try the curl command from within the container:</p> <pre class="">docker exec -it 76f4 curl http://api.open-notify.org/iss-now.json curl: (6) Could not resolve host: api.open-notify.org</pre> <p>So it was the container that could not resolve the domain name.</p> <p>After some research, I found that I need to run the docker image with the <em>&#8211;dns</em> parameter, which tells the container where to do DNS lookups. You can add multiple <em>&#8211;dns</em> parameters to your run command. I used it with Google&#8217;s DNS server and the one specified in my /etc/resolv.conf file. So the run command looks something like this:</p> <pre class="">docker run -d \ -p 1521:1521 \ -v /u01/oradata/xe:/u01/app/oracle \ --dns "some.ip.address.169" \ --dns "8.8.8.8" \ --name oracle_xe \ sath89/oracle-xe-11g</pre> <p>When I now try the curl command to test, I get the correct response:</p> <pre class="">$ docker exec -it 1234 curl http://api.open-notify.org/iss-now.json {"message": "success", "iss_position": {"longitude": "-73.8368", "latitude": "-49.7166"}, "timestamp": 1531176511}</pre> <p>Now trying it from inside the database, works, too:</p> <pre class="">SQL&gt; select utl_http.request('http://api.open-notify.org/iss-now.json') from dual; UTL_HTTP.REQUEST('HTTP://API.OPEN-NOTIFY.ORG/ISS-NOW.JSON') {"message": "success", "iss_position": {"longitude": "-67.2304", "latitude": "-48.1655"}, "timestamp": 1531176585}</pre> <p>BTW: Don&#8217;t forget to set your ACL!</p> Christoph Ruepprich http://ruepprich.wordpress.com/?p=2912 Tue Jul 10 2018 10:26:54 GMT-0400 (EDT) ORACLE APEX z MySQL http://apex.dbe.pl/2018/07/oracle-apex-z-mysql.html Podczas przeprowadzanych szkoleń dość często zdarzały nam się pytania od uczestników szkoleń: W jaki sposób podłączyć się do innych baz ? Mając to na uwadze oraz chwilę wolnego postanowiłem temat nieco rozpracować. Szukając najlepszego rozwiązania znalazłem klienta REST-owego dla MySQL-a oraz Postgres-a o nazwie <a href="http://restsql.org/doc/Overview.html">restSQL </a>: ). Po kilu dłuższych chwilach integracja zadziałała. Udało mi się wyświetlić dane z MySQL-a w raporcie interaktywnym a następnie przygotować formularz do edycji danych.<br /> <br /> <div style="text-align: center;"> Poniżej załączam wideo jak rozwiązanie działa.</div> <br /> <div class="separator" style="clear: both; text-align: center;"> <iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/Esyen1NXsbg/0.jpg" frameborder="0" height="460" src="https://www.youtube.com/embed/Esyen1NXsbg?feature=player_embedded" width="800"></iframe></div> <br /> <br /> <br /> <br /> <div style="text-align: center;"> Jeżeli jesteście zainteresowani szczegółami jak to zostało zrobione odsyłam do naszego angielsko-języcznego <b><a href="https://apexutil.blogspot.com/2018/07/oracle-apex-with-mysql.html" target="_blank">BLOGA</a></b></div> <div style="text-align: center;"> <br /></div> ) tag:blogger.com,1999:blog-7531463720728239813.post-1047558733334070056 Tue Jul 10 2018 08:31:00 GMT-0400 (EDT) APEX_ITEM Parte 3 Guardando automáticamente los valores de un apex_item con Ajax + Oracle Apex + Jquery https://aflorestorres.blogspot.com/2018/07/apexitem-parte-3-guardando.html Continuando con los apex_item, en esta oportunidad vamos a ver como usar datepicker, lista de valores y campos de input, haciendo que se guarden automaticamente, cada vez que modifiquemos algun valor.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-wCSVOQXzFFU/Wz7JB38aO2I/AAAAAAAAMnA/d35TbJnVV9YD-5dEWGMqEJGSiMXnJNM6wCLcBGAs/s1600/titulo.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="429" data-original-width="851" height="201" src="https://3.bp.blogspot.com/-wCSVOQXzFFU/Wz7JB38aO2I/AAAAAAAAMnA/d35TbJnVV9YD-5dEWGMqEJGSiMXnJNM6wCLcBGAs/s400/titulo.PNG" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"></div><br /><br /><br /><a href="https://aflorestorres.blogspot.com/2018/06/apexitem-parte-1-guardando-check-boxes.html" target="_blank">apex_item parte 1</a><br /><a href="https://aflorestorres.blogspot.com/2018/06/apexitem-parte-2-guardando-check-boxes.html" target="_blank">apex_item parte 2</a><br /><a href="https://aflorestorres.blogspot.com/2018/07/como-integrar-y-usar-plug-in-en-apex.html" target="_blank">como integrar alertify / plugin</a><br /><br /><a href="https://apex.oracle.com/pls/apex/f?p=32431:24:21489786515779::NO:::" target="_blank">Link demo:</a> user: demo/ pass: demo<br /><br />Video explicacion:<br /><div class="separator" style="clear: both; text-align: center;"><iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/hUu7-f4fBro/0.jpg" src="https://www.youtube.com/embed/hUu7-f4fBro?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div><br /><br /><br />Lo primero es crear un interactive report con la siguiente consulta, donde ya he creado mis apex_item de datepicker, lista de valores y entrada de texto.<br /><!-- HTML generated using hilite.me --><br /><div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">select</span> e<span style="color: #6600ee; font-weight: bold;">.</span>empno<br /> , e<span style="color: #6600ee; font-weight: bold;">.</span>ename<br /> <span style="color: #888888;">--, e.deptno</span><br /> <span style="color: #888888;">--, e.sal</span><br /> <span style="color: #888888;">--, e.hiredate</span><br /> <span style="color: #888888;">-- apex items</span><br /> , apex_item<span style="color: #6600ee; font-weight: bold;">.</span>hidden( p_idx <span style="color: #333333;">=&gt;</span> <span style="color: #6600ee; font-weight: bold;">1</span><br /> , p_value <span style="color: #333333;">=&gt;</span> e<span style="color: #6600ee; font-weight: bold;">.</span>empno) <span style="color: #333333;">||</span><br /> apex_item<span style="color: #6600ee; font-weight: bold;">.</span>date_popup2(p_idx <span style="color: #333333;">=&gt;</span> <span style="color: #6600ee; font-weight: bold;">2</span><br /> , p_value <span style="color: #333333;">=&gt;</span> e<span style="color: #6600ee; font-weight: bold;">.</span>hiredate<br /> , p_date_format <span style="color: #333333;">=&gt;</span> <span style="color: #996633;">:APP_DATE_TIME_FORMAT</span><br /> , p_size <span style="color: #333333;">=&gt;</span> <span style="color: #6600ee; font-weight: bold;">20</span>) hiredate<br /> , apex_item<span style="color: #6600ee; font-weight: bold;">.</span>select_list_from_lov(p_idx <span style="color: #333333;">=&gt;</span> <span style="color: #6600ee; font-weight: bold;">3</span><br /> , p_value <span style="color: #333333;">=&gt;</span> e<span style="color: #6600ee; font-weight: bold;">.</span>deptno<br /> , p_lov <span style="color: #333333;">=&gt;</span> <span style="background-color: #fff0f0;">'DEPARTAMENTOS'</span><br /> , p_attributes <span style="color: #333333;">=&gt;</span> <span style="background-color: #fff0f0;">'style="width: 200px;"'</span><br /> , p_show_null <span style="color: #333333;">=&gt;</span> <span style="background-color: #fff0f0;">'NO'</span>) deptno<br /> , apex_item<span style="color: #6600ee; font-weight: bold;">.</span><span style="color: #007020;">text</span>(p_idx <span style="color: #333333;">=&gt;</span> <span style="color: #6600ee; font-weight: bold;">4</span><br /> , p_value <span style="color: #333333;">=&gt;</span> e<span style="color: #6600ee; font-weight: bold;">.</span>sal<br /> , p_size <span style="color: #333333;">=&gt;</span> <span style="color: #6600ee; font-weight: bold;">5</span>) sal<br /> <span style="color: #008800; font-weight: bold;">from</span> emp e<br /></pre></div><br />Luego crearemos una accion dinamica para capturar el cambio de algun apex item en la region del reporte.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-gBqpHeAhUgA/Wz7Gq1RAQSI/AAAAAAAAMmo/AIGxHe77F80NA8jtURcwPg2rtYT3igBvACLcBGAs/s1600/1.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="182" data-original-width="695" src="https://4.bp.blogspot.com/-gBqpHeAhUgA/Wz7Gq1RAQSI/AAAAAAAAMmo/AIGxHe77F80NA8jtURcwPg2rtYT3igBvACLcBGAs/s1600/1.png" /></a><a href="https://4.bp.blogspot.com/-gBqpHeAhUgA/Wz7Gq1RAQSI/AAAAAAAAMmo/AIGxHe77F80NA8jtURcwPg2rtYT3igBvACLcBGAs/s1600/1.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a><a href="https://4.bp.blogspot.com/-gBqpHeAhUgA/Wz7Gq1RAQSI/AAAAAAAAMmo/AIGxHe77F80NA8jtURcwPg2rtYT3igBvACLcBGAs/s1600/1.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a></div><br /><!-- HTML generated using hilite.me --><br /><div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="background-color: #ffaaaa; color: red;">#</span>empleados_ir tr<span style="color: #333333;">:</span>gt(<span style="color: #0000dd; font-weight: bold;">1</span>)<br /><br />actualizarEmpleado(<span style="color: #008800; font-weight: bold;">this</span>.triggeringElement);<br /></pre></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-p76repIMglM/Wz7Gq5nAMEI/AAAAAAAAMmg/cyQDpOlMShAshJKBdUCD9bwxK5_5qTv1gCLcBGAs/s1600/2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="204" data-original-width="647" src="https://2.bp.blogspot.com/-p76repIMglM/Wz7Gq5nAMEI/AAAAAAAAMmg/cyQDpOlMShAshJKBdUCD9bwxK5_5qTv1gCLcBGAs/s1600/2.png" /></a></div><br />Creamos la funcion en la definicion de la pagina y hacemos el llamado al proceso ajax.<br /><br /><!-- HTML generated using hilite.me --><br /><div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">var</span> empno, hiredate, deptno, sal;<br /><br /><br /><span style="color: #008800; font-weight: bold;">function</span> actualizarEmpleado(elem){<br /><br /> empno <span style="color: #333333;">=</span> $(elem).find(<span style="background-color: #fff0f0;">"input[name='f01']"</span>).val();<br /> hiredate <span style="color: #333333;">=</span> $(elem).find(<span style="background-color: #fff0f0;">"input[name='f02']"</span>).val();<br /> deptno <span style="color: #333333;">=</span> $(elem).find(<span style="background-color: #fff0f0;">"select[name='f03']"</span>).val();<br /> sal <span style="color: #333333;">=</span> $(elem).find(<span style="background-color: #fff0f0;">"input[name='f04']"</span>).val(); <br /></pre><pre style="line-height: 125%; margin: 0;"> console.log(empno + ' / ' + hiredate + ' / ' + deptno + ' / ' + sal);</pre><pre style="line-height: 125%; margin: 0;"> ajax_process_actualizar(empno,hiredate,deptno,sal);<br /><br />}<br /><br /><br /><span style="color: #008800; font-weight: bold;">function</span> ajax_process_actualizar(empno,hiredate,deptno,sal){<br /><br /> apex.server.process(<span style="background-color: #fff0f0;">"ActualizarEmpleado"</span>,<br /> { x01<span style="color: #333333;">:</span> empno<br /> , x02<span style="color: #333333;">:</span> hiredate<br /> , x03<span style="color: #333333;">:</span> deptno<br /> , x04<span style="color: #333333;">:</span> sal <br /> }<br /> , {success<span style="color: #333333;">:</span> <span style="color: #008800; font-weight: bold;">function</span>(pData){ <br /> <br /> <span style="color: #008800; font-weight: bold;">if</span> (pData.ind_error <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">1</span>){<br /><br /> alertify.error(pData.mensaje);<br /> apex.event.trigger( <span style="background-color: #fff0f0;">"#empleados_ir"</span>, <span style="background-color: #fff0f0;">"apexrefresh"</span> );<br /> } <span style="color: #008800; font-weight: bold;">else</span> {<br /> alertify.success(pData.mensaje);<br /> }<br /><br /> }<br /> }<br /> <span style="color: #888888;">//, {dataType: "text"}</span><br /> ); <br />}<br /></pre></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-KsZ4VzArSBQ/Wz7Gq2O1qJI/AAAAAAAAMmk/SR77GAxjTro_esoupHfnzMIcqb1S34EywCLcBGAs/s1600/3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="291" data-original-width="735" src="https://2.bp.blogspot.com/-KsZ4VzArSBQ/Wz7Gq2O1qJI/AAAAAAAAMmk/SR77GAxjTro_esoupHfnzMIcqb1S34EywCLcBGAs/s1600/3.png" /></a></div><br /><br />Creamos el proceso ajax callback, que retorna el mensaje de actualizacion correcta o de error.<br /><br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-28S3T60eb58/Wz7Grg_o0EI/AAAAAAAAMms/7HVlb-HI8hUy_VDSi34t-14K2BjwqC35wCLcBGAs/s1600/4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="366" data-original-width="699" src="https://1.bp.blogspot.com/-28S3T60eb58/Wz7Grg_o0EI/AAAAAAAAMms/7HVlb-HI8hUy_VDSi34t-14K2BjwqC35wCLcBGAs/s1600/4.png" /></a></div><br /><!-- HTML generated using hilite.me --><br /><div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">begin</span><br /><br /> <span style="color: #008800; font-weight: bold;">update</span> emp<br /> <span style="color: #008800; font-weight: bold;">set</span> hiredate <span style="color: #333333;">=</span> to_date(apex_application.g_x02,:APP_DATE_TIME_FORMAT)<br /> , deptno <span style="color: #333333;">=</span> apex_application.g_x03<br /> , sal <span style="color: #333333;">=</span> apex_application.g_x04<br /> <span style="color: #008800; font-weight: bold;">where</span> empno <span style="color: #333333;">=</span> apex_application.g_x01;<br /><br /> apex_json.open_object;<br /> apex_json.<span style="color: #008800; font-weight: bold;">write</span>(p_name <span style="color: #333333;">=&gt;</span> <span style="background-color: #fff0f0;">'mensaje'</span>, p_value<span style="color: #333333;">=&gt;</span> <span style="background-color: #fff0f0;">'Actualizado correctamente'</span>);<br /> apex_json.<span style="color: #008800; font-weight: bold;">write</span>(p_name <span style="color: #333333;">=&gt;</span> <span style="background-color: #fff0f0;">'ind_error'</span>, p_value<span style="color: #333333;">=&gt;</span> <span style="color: #0000dd; font-weight: bold;">0</span>);<br /> apex_json.close_object;<br />exception<br /> <span style="color: #008800; font-weight: bold;">when</span> others <span style="color: #008800; font-weight: bold;">then</span><br /> apex_json.open_object;<br /> apex_json.<span style="color: #008800; font-weight: bold;">write</span>(p_name <span style="color: #333333;">=&gt;</span> <span style="background-color: #fff0f0;">'mensaje'</span>, p_value<span style="color: #333333;">=&gt;</span> <span style="background-color: #fff0f0;">'Error al actualizar'</span>);<br /> apex_json.<span style="color: #008800; font-weight: bold;">write</span>(p_name <span style="color: #333333;">=&gt;</span> <span style="background-color: #fff0f0;">'ind_error'</span>, p_value<span style="color: #333333;">=&gt;</span> <span style="color: #0000dd; font-weight: bold;">1</span>);<br /> apex_json.close_object;<br /><br /><span style="color: #008800; font-weight: bold;">end</span>;<br /></pre></div><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /> Angel O. Flores Torres tag:blogger.com,1999:blog-2893325831811936253.post-7791546017653997312 Thu Jul 05 2018 21:58:00 GMT-0400 (EDT) plsql collection lookup with multiple keys https://svenweller.wordpress.com/2018/07/05/plsql-collection-lookup-with-multiple-keys/ <h2>problem scenario</h2> <p>A <a href="https://community.oracle.com/thread/4156896" target="_blank" rel="noopener">recent question</a> on otn asked how to access a plsql collection using multiple keys.</p> <p>It is a typical scenario to build a second collection, to be able to access the main data in the first collection. The second collection fulfills the same role as an index on a table. It allows fast access to the main data record. I usually call the second collection an &#8220;index collection&#8221;.</p> <p>Here is an article by Steven Feuerstein who explains the concept of index collections in more detail: <a href="https://blogs.oracle.com/oraclemagazine/on-the-pga-and-indexing-collections" rel="nofollow">https://blogs.oracle.com/oraclemagazine/on-the-pga-and-indexing-collections</a></p> <p>But the forum question was not how to do a simple key =&gt; value lookup, but instead have two keys (based upon record set values) and use them to access the main collection.</p> <h2>solution</h2> <p>There are two general ways.<br /> Combine the keys into a single key or build a nested collection. I will show a quick example for both ways.</p> <h3>Way 1) Combined key</h3> <p>We can consolidate the two keys into one single key. Typically using some delimiter. And then use that combined key for the index_collection.</p> <p><code>combinedKey := key1||':'||key2;<br /> </code></p> <p>Of cause we need to make sure the delimiter is some value that does not exist in any of the keys.</p> <p><b>Example</b><br /> If you try to copy and run this example please note that the syntax highlighter removed the label &#8220;build_index&#8221;<br /> You might want to add this again, just after the &#8220;&#8211; index data&#8221; comment.</p> <pre class="brush: sql; highlight: [10,11]; title: ; notranslate"> set serveroutput on declare cursor c is (select trunc((level+2)/3) lvkey, chr(ASCII('A')+mod(level*2,3)) letter, round(dbms_random.value(1,100)) val from dual connect by level &lt;=10 ); type tabdata_t is table of c%rowtype index by binary_integer; tabdata tabdata_t; type keylookup_t is table of binary_integer index by varchar2(100); keylookup keylookup_t; begin -- load data open c; fetch c bulk collect into tabdata; -- notice no limit clause here. For larger record sets you need to use a loop and LIMIT! close c; -- index data &lt;&gt; for i in 1..tabdata.count loop keylookup(to_char(tabdata(i).lvKey)||':'||tabdata(i).letter) := i; end loop build_index; -- index is now complete. -- Test the index first dbms_output.put_line('Index 1B=&gt;'|| to_char(keylookup('1:B'))); dbms_output.put_line('Index 3A=&gt;'|| to_char(keylookup('3:A'))); -- now fetch the data using the index dbms_output.put_line('Data 1B=&gt;'|| tabdata(keylookup('1:B')).val); dbms_output.put_line('Data 3A=&gt;'|| tabdata(keylookup('3:A')).val); end; / </pre> <p>Output<br /> <code><br /> Index 1B=&gt;2<br /> Index 3A=&gt;9<br /> Data 1B=&gt;32<br /> Data 3A=&gt;67</code></p> <p>PL/SQL procedure successfully completed.</p> <h3>Way 2) collection of collection</h3> <p>A collection can be part of another collection. Nesting collections means we could do a lookup using two (or more) key values where each key is used for one collection.</p> <p><code>lookup(key1) =&gt; col2</code><br /> this returns a collection (e.g. col2). We can access the elements of the collection using the second key.</p> <p><code>col2(key2) =&gt; element</code></p> <p>or the short form:<br /> <code>lookup(key1)(key2) =&gt; element<br /> </code></p> <p>For readability we could add a record layer in between, but that is not neccessary.<br /> <code>lookup(key1).list(key2) =&gt; element<br /> </code></p> <p><b>Example</b><br /> Notice the definition of the index collection is in line 14 with the matching type definitions in line 11 and 12.</p> <pre class="brush: sql; highlight: [11,12,14]; title: ; notranslate"> set serveroutput on declare cursor c is (select trunc((level+2)/3) lvkey, chr(ASCII('A')+mod(level*2,3)) letter, round(dbms_random.value(1,100)) val from dual connect by level &lt;=10 ); type tabdata_t is table of c%rowtype index by binary_integer; tabdata tabdata_t; type letterlookup_t is table of binary_integer index by varchar2(10); type keylookup_t is table of letterlookup_t index by binary_integer; -- number not allowed! keylookup keylookup_t; empty_key letterlookup_t; begin -- load data open c; fetch c bulk collect into tabdata; -- notice no limit clause here. For larger record sets you need to use a loop and LIMIT! close c; -- index data &lt;&gt; for i in 1..tabdata.count loop if keylookup.exists(tabdata(i).lvKey) then if keylookup(tabdata(i).lvKey).exists(tabdata(i).letter) then -- same key twice? -- maybe add the values, maybe raise an error raise dup_val_on_index; else dbms_output.put_line('build index KEY='||tabdata(i).lvKey||',+letter='||tabdata(i).letter); keylookup(tabdata(i).lvKey)(tabdata(i).letter) := i; end if; else -- key not in index yet dbms_output.put_line('build index +KEY='||tabdata(i).lvKey||',+letter='||tabdata(i).letter); keylookup(tabdata(i).lvKey) := empty_key; keylookup(tabdata(i).lvKey)(tabdata(i).letter) := i; end if; end loop build_index; -- index is now complete. -- Lets access the data using some combinations of keyLv and letters -- Test the index first dbms_output.put_line('Index 1B=&gt;'|| to_char(keylookup(1)('B'))); dbms_output.put_line('Index 3A=&gt;'|| to_char(keylookup(3)('A'))); --dbms_output.put_line('1F='|| keylookup(1)('F')); -- this will raise NO_DATA_FOUND -- now fetch the data using the index dbms_output.put_line('Data 1B=&gt;'|| tabdata(keylookup(1)('B')).val); dbms_output.put_line('Data 3A=&gt;'|| tabdata(keylookup(3)('A')).val); end; / </pre> <p><code>Output<br /> build index +KEY=1,+letter=C<br /> build index KEY=1,+letter=B<br /> build index KEY=1,+letter=A<br /> build index +KEY=2,+letter=C<br /> build index KEY=2,+letter=B<br /> build index KEY=2,+letter=A<br /> build index +KEY=3,+letter=C<br /> build index KEY=3,+letter=B<br /> build index KEY=3,+letter=A<br /> build index +KEY=4,+letter=C<br /> Index 1B=&gt;2<br /> Index 3A=&gt;9<br /> Data 1B=&gt;62<br /> Data 3A=&gt;34</code></p> <p>PL/SQL procedure successfully completed.</p> <p>If we try to access a collection that does not exist we get an error (usually no_data_found). Since the index collections are always sparse, this is something to keep in mind. If you are not sure if the key combination is already indexed, then either check for existence or react on the NO_DATA_FOUND.</p> <h2>comparison</h2> <p>It is not easy to compare the two approaches. The first way looks slightly less complex. It depends also how familar other developers are with collections and especially with nested collections. For many the double parenthesis syntax &#8220;myCol()()&#8221; is a little complicated at the beginning.</p> <p>For very complex scenarios the first way might be the better way. It depends on data distribution (the more sparsly populated the key combinations are, the better is this way) and on how many keys (=dimensions) we have.</p> <p>I once measured the performance in a system where we needed 5 dimensions (5 different keys) to access some data. The combined key lookup was faster than building a complex collection of collection of collection of collection. But the additional time to concat the key values in the end also was a large performance burden.</p> <p>So in my specific case<br /> <code>lookup('A:B:C:D:E') &gt;&gt;&gt; lookup('A')('B')('C')('D')('E')<br /> </code><br /> I do not think this performance experience is representativ.</p> <h2>conclusion</h2> <p>It is possible to use two keys as an index collection to lookup data in the main collection. Nested collections is a tool that every plsql developer should know about. Only when we know our tools, we can decide when to use them or when not.</p> svenweller http://svenweller.wordpress.com/?p=7801 Thu Jul 05 2018 07:18:58 GMT-0400 (EDT) In the British APEX Community? Then UKOUG Tech18 is where you need to be! https://joelkallman.blogspot.com/2018/07/in-british-apex-community-then-ukoug.html <div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-CSn50SgrYeY/WzzVjxRpzaI/AAAAAAAADrM/_N5hC63KisEUQjLjdvDuWP_19xi05dwLQCLcBGAs/s1600/EnglandUSA.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="428" data-original-width="750" height="227" src="https://4.bp.blogspot.com/-CSn50SgrYeY/WzzVjxRpzaI/AAAAAAAADrM/_N5hC63KisEUQjLjdvDuWP_19xi05dwLQCLcBGAs/s400/EnglandUSA.jpeg" width="400" /></a></div><br />In 2003, even before <a href="https://apex.oracle.com/" target="_blank">Oracle APEX</a> had a real name (even before HTML DB), I had the good fortune of presenting APEX at the <a href="http://www.ukoug.org/" target="_blank">UKOUG</a> Tech conference in Birmingham, England.&nbsp; I was with my good friend <a href="https://www.linkedin.com/in/sergio/" target="_blank">Sergio Leunissen</a>, the original Product Manager of APEX.&nbsp; <a href="http://www.orafaq.com/wiki/Tom_Kyte" target="_blank">Tom Kyte</a> had kindly given us a few minutes on stage during his session to present Project Marvel.&nbsp; We were able to demonstrate marvel.oracle.com, a free, browser-based, hosted, multitenant, declarative (low code) development and runtime environment.&nbsp; This ultimately became today's <a href="https://apex.oracle.com/" target="_blank">https://apex.oracle.com</a>, which gets just around 2,000 new signups every week!<br /><br />Later that day, I also distinctly remember talking with an Oracle sales rep from the UK.&nbsp; I had explained that there were plans to include APEX (née Project Marvel) with Oracle Database and not charge any additional fee for it.&nbsp; He told me he thought it was a big mistake that Oracle wasn't planning on charging a customer for use of APEX, and unless there was a cost associated with it, there would be no perceived value and no one would use it.&nbsp; Here we are 15 years later.&nbsp; The industry has changed in extraordinary ways, and APEX and the APEX community continues to grow and expand at an accelerated rate.&nbsp; And in 2018, when everyone expects tools and frameworks to be "free", I remain convinced that we made the right decision to include APEX with Oracle Database and not make it a for-cost option.<br /><br />I am looking forward to returning to <a href="http://www.ukoug.org/other/conferences2018/" target="_blank">UKOUG Tech18</a> this year, where a lot of the original APEX community outreach began for us.&nbsp; Some of my favorite customers are in the United Kingdom, and I've known and worked with a large number of them for many years.&nbsp; The fine folks at <a href="http://www.ukoug.org/" target="_blank">UKOUG</a> have graciously given me the opportunity to present the APEX Community Keynote on Monday, December 3, 2018.&nbsp; It will be "Oracle APEX: State of the Union", and this will be a presentation on both what is happening for APEX inside of Oracle and also across the APEX community globally.&nbsp; We will be in Liverpool Sunday through Wednesday, and we look forward to meeting as many customers as possible.&nbsp; You have a story to tell and we'd like to hear it, and how we can help.<br /><br />See you in Liverpool in December 2018! Joel R. Kallman tag:blogger.com,1999:blog-12214002.post-4653715039843459089 Wed Jul 04 2018 10:31:00 GMT-0400 (EDT) How to create a web application using the new wizard in APEX 18.1 [Video 03 - English] http://feedproxy.google.com/~r/DescubriendoElMundoDeOracle/~3/tICrMw-Rpi0/how-to-create-web-application-using-new.html <div style="text-align: center;"><iframe allow="autoplay; encrypted-media" allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/q9q8HdCzeY4" width="560"></iframe></div><img src="http://feeds.feedburner.com/~r/DescubriendoElMundoDeOracle/~4/tICrMw-Rpi0" height="1" width="1" alt=""/> Clarisa J. Maman Orfali tag:blogger.com,1999:blog-1315583943401206186.post-2530004575213987478 Tue Jul 03 2018 14:17:00 GMT-0400 (EDT) Cómo crear nuestra primera aplicación en APEX 18.1 - [Video 03 - Español] http://feedproxy.google.com/~r/DescubriendoElMundoDeOracle/~3/fxEewpCet2s/como-crear-nuestra-primera-aplicacion.html <div style="text-align: center;"><iframe allow="autoplay; encrypted-media" allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/E_sU8BubVj0" width="560"></iframe></div><img src="http://feeds.feedburner.com/~r/DescubriendoElMundoDeOracle/~4/fxEewpCet2s" height="1" width="1" alt=""/> Clarisa J. Maman Orfali tag:blogger.com,1999:blog-1315583943401206186.post-816211484141643666 Tue Jul 03 2018 14:15:00 GMT-0400 (EDT) Como integrar y usar plug-in en Apex / Alertify + Oracle Apex + JavaScript (notificaciones/alertas) https://aflorestorres.blogspot.com/2018/07/como-integrar-y-usar-plug-in-en-apex.html En esta&nbsp;oportunidad veremos&nbsp;como integrar el plugin alertify en Apex. y veremos dos formas de poderlo usar. Con una accion dinamica custom o con javaScript.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-caIWwiyq5OQ/WzmqyRMobLI/AAAAAAAAMkg/smfbvvgSyDQLBmbutJ1AG2hOiHCzTYVBACLcBGAs/s1600/presentacion.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="431" data-original-width="805" height="213" src="https://2.bp.blogspot.com/-caIWwiyq5OQ/WzmqyRMobLI/AAAAAAAAMkg/smfbvvgSyDQLBmbutJ1AG2hOiHCzTYVBACLcBGAs/s400/presentacion.PNG" width="400" /></a></div><br /><br />Este plugin da al usuario una mejor experiencia de uso al tener notificaciones con un buen diseño.<br />Cabe mencionar que este plug-in fue construido en base a <a href="http://fabien-d.github.io/alertify.js/" target="_blank">esta libreria de JS</a><br /><br /><a href="http://apex-plugin.com/oracle-apex-plugins/dynamic-action-plugin/alertify_349.html" target="_blank">Link de descarga</a> Alertify como plugin<br /><a href="https://apex.oracle.com/pls/apex/f?p=64237:30" target="_blank">Link demo</a> propia del autor.<br /><br /><a href="https://apex.oracle.com/pls/apex/f?p=32431:26:10093185978562:::::" target="_blank">Link mi aplicacion demo&nbsp;</a><br /><br />Video demo<br /><br /><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/gtx8r-xZPxg/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/gtx8r-xZPxg?feature=player_embedded" width="320"></iframe></div><br /><br /><br />Lo primero que use es crear una accion dinamica CUSTOM<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-TQeU0F0Ymlg/WzmsP-1sslI/AAAAAAAAMkw/ICmWUEhYjw897kWtqsWznHNNrrptX9jZgCEwYBhgL/s1600/1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="397" data-original-width="697" src="https://1.bp.blogspot.com/-TQeU0F0Ymlg/WzmsP-1sslI/AAAAAAAAMkw/ICmWUEhYjw897kWtqsWznHNNrrptX9jZgCEwYBhgL/s1600/1.png" /></a></div><br />y seleccionamos una accion de tipo alertify<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-dyyevoLKaLY/WzmsP_NGtVI/AAAAAAAAMk0/c2WCJbZUYbAY7lklvMtMmTWBcjpODMgYQCEwYBhgL/s1600/2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="217" data-original-width="599" src="https://4.bp.blogspot.com/-dyyevoLKaLY/WzmsP_NGtVI/AAAAAAAAMk0/c2WCJbZUYbAY7lklvMtMmTWBcjpODMgYQCEwYBhgL/s1600/2.png" /></a></div><br /><br />En mi boton de comprobar, llamare un javascript que compruebe si mi item tiene o no valor.<br /><br /><!-- HTML generated using hilite.me --><br /><div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">if</span> ($(<span style="background-color: #fff0f0;">"#P26_TIENE_VALOR"</span>).val())<br />{<br /> $.event.trigger(<span style="background-color: #fff0f0;">"mostrar_mensaje_correcto"</span>);<br />}<br /><span style="color: #008800; font-weight: bold;">else</span>{<br /> $.event.trigger(<span style="background-color: #fff0f0;">"mostrar_mensaje_error"</span>); <br />}<br /></pre></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-lBz4zRbVP14/WzmsP3gix9I/AAAAAAAAMk8/T7I4zUVGBmMGTl840LMI7vdON0f9sMGkwCEwYBhgL/s1600/3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="301" data-original-width="692" src="https://1.bp.blogspot.com/-lBz4zRbVP14/WzmsP3gix9I/AAAAAAAAMk8/T7I4zUVGBmMGTl840LMI7vdON0f9sMGkwCEwYBhgL/s1600/3.png" /></a></div><br /><br />Resultado:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/--MG_MOvrs7s/WzmteEzIJnI/AAAAAAAAMlU/Jd-TCFP1B5cxCzBRvkrNHuVPq9s26rl_ACLcBGAs/s1600/5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="225" data-original-width="767" src="https://3.bp.blogspot.com/--MG_MOvrs7s/WzmteEzIJnI/AAAAAAAAMlU/Jd-TCFP1B5cxCzBRvkrNHuVPq9s26rl_ACLcBGAs/s1600/5.png" /></a></div><br /><br /><br />Y la otra forma de usar este plug in es llamarlo, directamente en un javaScript:<br />* nota podemos usar la documentacion oficial para su uso. <a href="http://fabien-d.github.io/alertify.js/" target="_blank">aqui</a><br /><br /><!-- HTML generated using hilite.me --><br /><div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #888888;">// alert dialog</span><br />alertify.alert(<span style="background-color: #fff0f0;">"Message"</span>);<br /><br /><span style="color: #888888;">// success notification</span><br /><span style="color: #888888;">// shorthand for alertify.log("Notification", "success");</span><br />alertify.success(<span style="background-color: #fff0f0;">"Success notification"</span>);<br /></pre></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-UruTPQ9Wf2w/WzmsQCDIilI/AAAAAAAAMlI/9wS7n4iayFs5cvSFzILpOu5oaaLWnNgfACEwYBhgL/s1600/4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="327" data-original-width="678" src="https://3.bp.blogspot.com/-UruTPQ9Wf2w/WzmsQCDIilI/AAAAAAAAMlI/9wS7n4iayFs5cvSFzILpOu5oaaLWnNgfACEwYBhgL/s1600/4.png" /></a></div><br /><br /><br /><br /><br /><br /> Angel O. Flores Torres tag:blogger.com,1999:blog-2893325831811936253.post-6077383902982670651 Mon Jul 02 2018 10:19:00 GMT-0400 (EDT) It was a Labor of .... well it took a bit of work. http://acitemreh.blogspot.com/2018/07/it-was-labor-of-well-it-took-bit-of-work.html It has been a while. For a lot of things and for a lot of reasons.&nbsp; Today I want to extend a greeting to all those serving in uniform no matter your country.&nbsp; As the US celebrates its Independence Day, I recognize that those in uniform bear the brunt of diplomacy and its failings but the service you provide is invaluable to those that you serve.&nbsp; I wish you all Peace now and in the future.<br /><br />This latest post is to commemorate the first real showcase of a project that I have been working on for a while. It's origins go back as far as when I first began to use Application Express.&nbsp; I had worked with several other systems that included a workflow component and almost immediately felt the absence of one in the APEX offerings.&nbsp;<br />&nbsp; I began with the idea, it matured into a design, then to code, and finally it got a name "Relay".&nbsp; &nbsp;I originally thought that Domino might be better but IBM already had a product with that name, and I was uncomfortable with the idea that the perception of the name included a lot of work with one good show at the end.<br /><a href="https://youtu.be/N56G9VYbmtg" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;" target="_blank"><img border="0" data-original-height="233" data-original-width="331" height="140" src="https://1.bp.blogspot.com/-8wmcJfp_4Sg/WzlohrZw5TI/AAAAAAAAAZE/xrWBwAsRiM8EBbaEJnAVoWSjrKIKnlmcQCLcBGAs/s200/7-1-2018%2B5-34-07%2BPM.png" width="200" /></a>&nbsp; Over the years I worked, here, there; whenever I had some time in my life with my wife, (her patience with this should be notably appreciated), my two sons, and a full-time career.&nbsp; Now, I have come to a point where I'd really like to show some of what it means to have workflow in your applications.&nbsp; Today I uploaded a short (25min) video to youtube.com.&nbsp; You can find the video here (https://youtu.be/N56G9VYbmtg) or by clicking the logo.<br />I am hoping that Relay will fill the gap I have seen for far too long in APEX and allow us to redefine some of how we create our applications in the future.&nbsp;<br /><br />There will be questions, I know this.&nbsp; There will be comments, I know that too.&nbsp; There will also be more videos and posts from me as I show more of what this has become.&nbsp; Please tell me what you think.&nbsp; As for release and a decision on commercial availability, I am leaving that as an open-ended topic for the moment but I am open to thoughts here as well.<br /><br />Enjoy! Jason D. Aughenbaugh tag:blogger.com,1999:blog-21645351.post-1493888891444438140 Sun Jul 01 2018 20:17:00 GMT-0400 (EDT) APEX_ITEM Parte 2 Guardando Check Boxes con Ajax y manteniendo el valor en paginación + Oracle Apex + Jquery https://aflorestorres.blogspot.com/2018/06/apexitem-parte-2-guardando-check-boxes.html Buen dia , continuando con el manejo de apex_items, hoy veremos como guardar el valor de un checkbox sin necesidad de hacer submit a la pagina y manteniendo el valor si&nbsp; usamos la paginacion en un reporte.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-96_xaiY6_uY/Wy8Dxe-BL8I/AAAAAAAAMbo/zieW8CsWoWcZf2k7Rh7mXruY3HQw_NaqgCLcBGAs/s1600/parte_2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="415" data-original-width="826" height="160" src="https://2.bp.blogspot.com/-96_xaiY6_uY/Wy8Dxe-BL8I/AAAAAAAAMbo/zieW8CsWoWcZf2k7Rh7mXruY3HQw_NaqgCLcBGAs/s320/parte_2.PNG" width="320" /></a></div><br /><br /><a href="https://aflorestorres.blogspot.com/2018/06/apexitem-parte-1-guardando-check-boxes.html" target="_blank">En mi anterior tutorial veiamos&nbsp; el manejo simple de un checkbox</a><br /><br />Para este fin vamos a usar:<br /><br /><ul><li>Colecciones / Collections</li><li>Ajax /&nbsp;apex.server.process</li><li>Interactive report</li><li>PlSql</li></ul><div>Video demo:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/Q7tgKTD7fNk/0.jpg" src="https://www.youtube.com/embed/Q7tgKTD7fNk?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div><div><br /></div><div><br /></div><div><a href="https://apex.oracle.com/pls/apex/f?p=32431:22:110301651209453::NO:::" target="_blank">Link demo apex</a>, user: demo / pass: demo</div><div><br /></div><div>Primero crearemos una coleccion, nombre: 'EMPLEADOS_COL' , y se creara a partir de un query de los empleados, notemos que tengo una columna donde me indica si el empleado pertenece al departamento seleccionado.<br /><br /><a href="https://docs.oracle.com/cd/E71588_01/AEAPI/CREATE_COLLECTION_FROM_QUERY_B-Procedure.htm#AEAPI730" target="_blank">Documentacion&nbsp; de colecciones</a><br /><br /><!-- HTML generated using hilite.me --><br /><div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">declare</span><br /> l_sql varchar2(<span style="color: #0000dd; font-weight: bold;">4000</span>);<br /> l_nombre_coleccion varchar2(<span style="color: #0000dd; font-weight: bold;">4000</span>) :<span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'EMPLEADOS_COL'</span>;<br /><span style="color: #008800; font-weight: bold;">begin</span><br /><br /> if apex_collection.collection_exists (p_collection_name <span style="color: #333333;">=&gt;</span> l_nombre_coleccion)<br /> <span style="color: #008800; font-weight: bold;">then</span><br /> apex_collection.delete_collection(p_collection_name <span style="color: #333333;">=&gt;</span> l_nombre_coleccion);<br /> <span style="color: #008800; font-weight: bold;">end</span> if;<br /><br /> l_sql :<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">'select empno</span><br /><span style="background-color: #fff0f0;"> , ename</span><br /><span style="background-color: #fff0f0;"> , deptno</span><br /><span style="background-color: #fff0f0;"> , sal</span><br /><span style="background-color: #fff0f0;"> , case when deptno = :P23_DEPARTAMENTO then 1 else 0 end pertenece</span><br /><span style="background-color: #fff0f0;"> , 0 ind_cambio</span><br /><span style="background-color: #fff0f0;"> from emp'</span>;<br /><br /> apex_collection.create_collection_from_query_b<br /> (<br /> p_collection_name <span style="color: #333333;">=&gt;</span> l_nombre_coleccion<br /> , p_query <span style="color: #333333;">=&gt;</span> l_sql<br /> , p_names <span style="color: #333333;">=&gt;</span> apex_util.string_to_table(<span style="background-color: #fff0f0;">'P23_DEPARTAMENTO'</span>)<br /> , p_values <span style="color: #333333;">=&gt;</span> apex_util.string_to_table(:P23_DEPARTAMENTO)<br /> );<br /><br /><span style="color: #008800; font-weight: bold;">end</span>;<br /></pre></div><br /><br />Luego usaremos crearemos un reporte con la coleccion, aqui agregaremos el apex_item.checkbox2.<br /><br /><!-- HTML generated using hilite.me --><br /><div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">select</span> seq_id<br /> , c001 empno<br /> , c002 ename<br /> , c003 deptno<br /> , c004 sal<br /> , apex_item.hidden(p_idx <span style="color: #333333;">=&gt;</span> <span style="color: #0000dd; font-weight: bold;">1</span><br /> , p_value <span style="color: #333333;">=&gt;</span> seq_id) <span style="color: #333333;">||</span><br /> apex_item.checkbox2(p_idx <span style="color: #333333;">=&gt;</span> <span style="color: #0000dd; font-weight: bold;">2</span><br /> , p_value <span style="color: #333333;">=&gt;</span> c005<br /> , p_checked_values <span style="color: #333333;">=&gt;</span> <span style="color: #0000dd; font-weight: bold;">1</span>) pertenece<br /> , c006 ind_cambio<br /> <span style="color: #008800; font-weight: bold;">from</span> apex_collections<br /> <span style="color: #008800; font-weight: bold;">where</span> collection_name <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'EMPLEADOS_COL'</span><br /></pre></div><br />Luego crearemos una accion dinamica para capturar el click en el checkbox.<br /><br />Dentro crearemos una accion de JavaScript, aqui llamaremos un proceso AJAX (apex.server.process), para actualizar la coleccion.<br /><!-- HTML generated using hilite.me --><br /><div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0;">console.log(<span style="color: #008800; font-weight: bold;">this</span>.triggeringElement);<br /><br /><span style="color: #008800; font-weight: bold;">var</span> elem <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">this</span>.triggeringElement;<br /><span style="color: #008800; font-weight: bold;">var</span> estaMarcado <span style="color: #333333;">=</span> $(elem).is(<span style="background-color: #fff0f0;">':checked'</span>);<br /><span style="color: #008800; font-weight: bold;">var</span> seqId <span style="color: #333333;">=</span> $(elem).parent().find(<span style="background-color: #fff0f0;">"input[name='f01']"</span>).val();<br /><br /><span style="color: #888888;">//console.log(estaMarcado);</span><br /><span style="color: #888888;">//console.log(seqId);</span><br /><br />apex.server.process(<span style="background-color: #fff0f0;">"Actualizar_Coleccion"</span>,<br /> { x01<span style="color: #333333;">:</span> seqId<br /> , x02<span style="color: #333333;">:</span> estaMarcado<br /> } <br /> , {success<span style="color: #333333;">:</span> <span style="color: #008800; font-weight: bold;">function</span>(pdata){<br /> console.log(pdata.mensaje); <br /> }<br /> }<br /> <span style="color: #888888;">// , {dataType: "text"}</span><br /> );<br /> <br /></pre></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-n9TXxdPB-Fo/WzB1M9HxB-I/AAAAAAAAMcE/1Fy4NWtbsj8RZfWAsFWNr8Tvt3fpeV5wwCLcBGAs/s1600/check_box_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="332" data-original-width="363" src="https://3.bp.blogspot.com/-n9TXxdPB-Fo/WzB1M9HxB-I/AAAAAAAAMcE/1Fy4NWtbsj8RZfWAsFWNr8Tvt3fpeV5wwCLcBGAs/s1600/check_box_1.png" /></a></div><br /><br /><br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-BJsIRNTpMi4/WzB1M10nuAI/AAAAAAAAMcI/8Js-9yRrbecbsiYX9mianMBbfN6x2YlLwCEwYBhgL/s1600/check_box_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="292" data-original-width="567" src="https://1.bp.blogspot.com/-BJsIRNTpMi4/WzB1M10nuAI/AAAAAAAAMcI/8Js-9yRrbecbsiYX9mianMBbfN6x2YlLwCEwYBhgL/s1600/check_box_2.png" /></a></div><br />En el proceso AJAX .<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-JwHnfj4U7ZM/WzB1M_KUpLI/AAAAAAAAMcQ/otgo9d7CH2wYnzkfBjiS2K3ahsxUDMIWACEwYBhgL/s1600/check_box_3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="363" data-original-width="654" src="https://2.bp.blogspot.com/-JwHnfj4U7ZM/WzB1M_KUpLI/AAAAAAAAMcQ/otgo9d7CH2wYnzkfBjiS2K3ahsxUDMIWACEwYBhgL/s1600/check_box_3.png" /></a></div><br /><br />* Actualizamos el atributo 6 del coleccion que es nuestro indicador que hubo un cambio en ese registro.<br />* Actualizamos el atributo 5 con 1 si esta el valor CHECKED y 0 si no lo es.<br />* Escribimos un objeto JSON para luego si deseamos personalizar el mensaje de nuestro cambio.<br /><br /><!-- HTML generated using hilite.me --><br /><div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">begin</span><br /> apex_collection.update_member_attribute (<br /> p_collection_name <span style="color: #333333;">=&gt;</span> <span style="background-color: #fff0f0;">'EMPLEADOS_COL'</span>,<br /> p_seq <span style="color: #333333;">=&gt;</span> apex_application.g_x01,<br /> p_attr_number <span style="color: #333333;">=&gt;</span> <span style="color: #0000dd; font-weight: bold;">5</span>,<br /> p_attr_value <span style="color: #333333;">=&gt;</span> <span style="color: #008800; font-weight: bold;">case</span> <span style="color: #008800; font-weight: bold;">when</span> apex_application.g_x02 <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'true'</span> <span style="color: #008800; font-weight: bold;">then</span> <span style="background-color: #fff0f0;">'1'</span> <span style="color: #008800; font-weight: bold;">else</span> <span style="background-color: #fff0f0;">'0'</span> <span style="color: #008800; font-weight: bold;">end</span><br /> );<br /> <br /> apex_collection.update_member_attribute (<br /> p_collection_name <span style="color: #333333;">=&gt;</span> <span style="background-color: #fff0f0;">'EMPLEADOS_COL'</span>,<br /> p_seq <span style="color: #333333;">=&gt;</span> apex_application.g_x01,<br /> p_attr_number <span style="color: #333333;">=&gt;</span> <span style="color: #0000dd; font-weight: bold;">6</span>,<br /> p_attr_value <span style="color: #333333;">=&gt;</span> <span style="color: #0000dd; font-weight: bold;">1</span><br /> ); <br /> <br /> apex_json.open_object; <br /> apex_json.<span style="color: #008800; font-weight: bold;">write</span>(p_name <span style="color: #333333;">=&gt;</span> <span style="background-color: #fff0f0;">'mensaje'</span>, p_value<span style="color: #333333;">=&gt;</span> <span style="background-color: #fff0f0;">'Actualizado correctamente'</span>); <br /> apex_json.close_object;<br />exception<br /> <span style="color: #008800; font-weight: bold;">when</span> others <span style="color: #008800; font-weight: bold;">then</span><br /> apex_json.open_object; <br /> apex_json.<span style="color: #008800; font-weight: bold;">write</span>(p_name <span style="color: #333333;">=&gt;</span> <span style="background-color: #fff0f0;">'mensaje'</span>, p_value<span style="color: #333333;">=&gt;</span> <span style="background-color: #fff0f0;">'Error al actualizar'</span>);<br /> apex_json.close_object;<br /><br /><span style="color: #008800; font-weight: bold;">end</span>;<br /></pre></div><br />Finalmente creamos un proceso Pl/Sql para actualizar los valores en tabla.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-8hc7pV9N8YI/WzB1NZ5XKqI/AAAAAAAAMcY/oXCzMg5HCx8exmyjaxsCs4xCiIkPiOLDACEwYBhgL/s1600/check_box_4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="380" data-original-width="671" src="https://1.bp.blogspot.com/-8hc7pV9N8YI/WzB1NZ5XKqI/AAAAAAAAMcY/oXCzMg5HCx8exmyjaxsCs4xCiIkPiOLDACEwYBhgL/s1600/check_box_4.png" /></a></div><br /><br /><br />* Notemos que en el proceso de ajax podemos hacer esta actualizacion.<br /><br /><!-- HTML generated using hilite.me --><br /><div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">for</span> c_emp <span style="color: #008800; font-weight: bold;">in</span> (<span style="color: #008800; font-weight: bold;">select</span> c001 empno<br /> , c005 pertenece <span style="color: #888888;">-- c005 es de pertenencia </span><br /> <span style="color: #008800; font-weight: bold;">from</span> apex_collections<br /> <span style="color: #008800; font-weight: bold;">where</span> collection_name <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'EMPLEADOS_COL'</span><br /> <span style="color: #008800; font-weight: bold;">and</span> c006 <span style="color: #333333;">!=</span> <span style="color: #0000dd; font-weight: bold;">0</span> <span style="color: #888888;">-- todos los que han cambiado de valor </span><br />)<br />loop<br /><br /> if c_emp.pertenece <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1</span> <span style="color: #008800; font-weight: bold;">then</span> <br /> <span style="color: #008800; font-weight: bold;">update</span> emp<br /> <span style="color: #008800; font-weight: bold;">set</span> deptno <span style="color: #333333;">=</span> :P22_DEPARTAMENTO<br /> <span style="color: #008800; font-weight: bold;">where</span> empno <span style="color: #333333;">=</span> c_emp.empno; <br /> <br /> <span style="color: #008800; font-weight: bold;">else</span> <br /> <span style="color: #008800; font-weight: bold;">update</span> emp<br /> <span style="color: #008800; font-weight: bold;">set</span> deptno <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">null</span><br /> <span style="color: #008800; font-weight: bold;">where</span> empno <span style="color: #333333;">=</span> c_emp.empno; <br /> <span style="color: #008800; font-weight: bold;">end</span> if;<br /> <br /><span style="color: #008800; font-weight: bold;">end</span> loop;<br /></pre></div><br /><br /><br /><br /><br /><br /><br /><br /></div><br /><br /> Angel O. Flores Torres tag:blogger.com,1999:blog-2893325831811936253.post-1111053732180612198 Sat Jun 30 2018 19:47:00 GMT-0400 (EDT) Automatically capture all errors and context in your APEX application http://dgielis.blogspot.com/2018/06/automatically-capture-all-errors-and.html Let me start this post with a conversation between an end-user (Sarah) and a developer (Harry):<br /><br />End-user: <i>"Hey there, I'm receiving an error in the app."</i><br /><b>Developer:</b> <i>"Oh, sorry to hear that. What is the message saying?"</i><br />End-user:<i> "Unable to process row of table EBA_PROJ_STATUS_CATS. &nbsp;</i><i>ORA-02292: integrity constraint (XXX.SYS_C0090660) violated - child record found"</i><br /><b>Developer: </b><i>"Oh, what are you trying to do?"</i><br />End-user:<i>&nbsp;"I'm trying to delete a category."</i><br /><b>Developer:&nbsp;</b><i>"Oh, most likely this category is in use, so you can't delete the category, you first need ..."</i><br />End-user:<i>&nbsp;"Ehh?!"</i><br /><div><br /></div><div>You might ask yourself, what is wrong with this conversation?</div><div><br /></div><div>The first thing is that the end-user gets an error which is hard to understand. She probably got the error before but tried a few times before calling the developer (or support). Most likely Sarah has a tight deadline and these errors don't really help their mood.&nbsp;</div><div>The other problem is that the developer was most likely just busy working on some complex logic and now gets interrupted. It takes some minutes before Harry can understand what Sarah is talking about. He needs to ask a few questions to know what Sarah is doing and doesn't have much context. He might ask to send a screenshot of the error and a few minutes later he receives this (app in APEX 5.1):</div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-HI-SD001zZs/WzfhmHbRN2I/AAAAAAAAJQU/wRkPQd3nZL8Yp0xE0unVEvclbGb-NwsggCLcBGAs/s1600/apex51.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="512" data-original-width="818" height="250" src="https://1.bp.blogspot.com/-HI-SD001zZs/WzfhmHbRN2I/AAAAAAAAJQU/wRkPQd3nZL8Yp0xE0unVEvclbGb-NwsggCLcBGAs/s400/apex51.png" width="400" /></a></div><br /></div><div>Harry is a smart cookie, so he knows in which schema to look for that constraint name, so he knows which table it's linked to. If Harry read <a href="http://dgielis.blogspot.com/2018/06/error-whats-going-in-apex-easiest-way.html">my previous blog post</a> on how to remotely see what Sarah was doing, he has more context too.</div><div><br />If the application is running in APEX 18.1, it's a different story. The screenshot will look like this:<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-uLMe0J8uvi8/WzfhkyMIn6I/AAAAAAAAJQQ/ksTYKtejzJwQddUc5bCdIC5V_bf_Qwb5ACLcBGAs/s1600/apex181.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="450" data-original-width="1264" height="226" src="https://1.bp.blogspot.com/-uLMe0J8uvi8/WzfhkyMIn6I/AAAAAAAAJQQ/ksTYKtejzJwQddUc5bCdIC5V_bf_Qwb5ACLcBGAs/s640/apex181.png" width="640" /></a></div><br />APEX 18.1 actually enhanced the default error message. The user gets fewer details and sees a debug id. With this debug id the developer can get actually more info in Your App &gt; Utilities &gt; Debug Messages:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-uPVWFJvCflM/WzfjQzC76yI/AAAAAAAAJQk/M4RfBizs4qY72-N7Yxw8FiZ88CCV56VQQCLcBGAs/s1600/Screen%2BShot%2B2018-06-30%2Bat%2B22.08.08.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1104" data-original-width="1600" height="440" src="https://3.bp.blogspot.com/-uPVWFJvCflM/WzfjQzC76yI/AAAAAAAAJQk/M4RfBizs4qY72-N7Yxw8FiZ88CCV56VQQCLcBGAs/s640/Screen%2BShot%2B2018-06-30%2Bat%2B22.08.08.png" width="640" /></a></div><br />You might also want to check this&nbsp;<a href="https://joelkallman.blogspot.com/2017/01/details-about-this-incident-are.html">blog post</a>&nbsp;by Joel Kallman where to find more info when receiving an internal error with debug&nbsp;id.<br /><br />Although APEX 18.1 captures more info, there's a more recommended way to deal with errors.<br /><br /></div><div>In APEX you can define an Error Handling Function which will kick in every time an error occurs.&nbsp;You can define this function in the Application Definition:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-YPhDyG1t-C8/WzeWhtXERmI/AAAAAAAAJP8/mN369ntmsCgkTskEzN3RcIC6uz9R8GQJgCLcBGAs/s1600/ora_apex_error_handling_function.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="617" data-original-width="1600" height="246" src="https://1.bp.blogspot.com/-YPhDyG1t-C8/WzeWhtXERmI/AAAAAAAAJP8/mN369ntmsCgkTskEzN3RcIC6uz9R8GQJgCLcBGAs/s640/ora_apex_error_handling_function.png" width="640" /></a></div><div><br /></div><div>When you look in the Packaged applications that are shipped with Oracle Application Express (APEX), you find some examples. The above screenshot comes from P-Track.</div><div><br />The error handling function has this definition:<br /><br /><code> function apex_error_handling (p_error in apex_error.t_error )<br />&nbsp; return apex_error.t_error_result<br /></code></div><div><br />The example used in P-Track gives a good overview (read the comments in the package) of the different errors you want to capture:<br /><code><br />function apex_error_handling (<br />&nbsp; &nbsp; p_error in apex_error.t_error )<br />&nbsp; &nbsp; return apex_error.t_error_result<br />is<br />&nbsp; &nbsp; l_result &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;apex_error.t_error_result;<br />&nbsp; &nbsp; l_constraint_name varchar2(255);<br />begin<br />&nbsp; &nbsp; l_result := apex_error.init_error_result (<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; p_error =&gt; p_error );<br />&nbsp; &nbsp; -- If it is an internal error raised by APEX, like an invalid statement or<br />&nbsp; &nbsp; -- code which can not be executed, the error text might contain security sensitive<br />&nbsp; &nbsp; -- information. To avoid this security problem we can rewrite the error to<br />&nbsp; &nbsp; -- a generic error message and log the original error message for further<br />&nbsp; &nbsp; -- investigation by the help desk.<br />&nbsp; &nbsp; if p_error.is_internal_error then<br />&nbsp; &nbsp; &nbsp; &nbsp; -- mask all errors that are not common runtime errors (Access Denied<br />&nbsp; &nbsp; &nbsp; &nbsp; -- errors raised by application / page authorization and all errors<br />&nbsp; &nbsp; &nbsp; &nbsp; -- regarding session and session state)<br />&nbsp; &nbsp; &nbsp; &nbsp; if not p_error.is_common_runtime_error then<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; add_error_log( p_error );<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -- Change the message to the generic error message which doesn't expose<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -- any sensitive information.<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; l_result.message := 'An unexpected internal application error has occurred.';<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; l_result.additional_info := null;<br />&nbsp; &nbsp; &nbsp; &nbsp; end if;<br />&nbsp; &nbsp; else<br />&nbsp; &nbsp; &nbsp; &nbsp; -- Always show the error as inline error<br />&nbsp; &nbsp; &nbsp; &nbsp; -- Note: If you have created manual tabular forms (using the package<br />&nbsp; &nbsp; &nbsp; &nbsp; -- &nbsp; &nbsp; &nbsp; apex_item/htmldb_item in the SQL statement) you should still<br />&nbsp; &nbsp; &nbsp; &nbsp; -- &nbsp; &nbsp; &nbsp; use "On error page" on that pages to avoid loosing entered data<br />&nbsp; &nbsp; &nbsp; &nbsp; l_result.display_location := case<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;when l_result.display_location = apex_error.c_on_error_page then apex_error.c_inline_in_notification<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;else l_result.display_location<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;end;<br />&nbsp; &nbsp; &nbsp; &nbsp; -- If it's a constraint violation like<br />&nbsp; &nbsp; &nbsp; &nbsp; --<br />&nbsp; &nbsp; &nbsp; &nbsp; -- &nbsp; -) ORA-00001: unique constraint violated<br />&nbsp; &nbsp; &nbsp; &nbsp; -- &nbsp; -) ORA-02091: transaction rolled back (can hide a deferred constraint)<br />&nbsp; &nbsp; &nbsp; &nbsp; -- &nbsp; -) ORA-02290: check constraint violated<br />&nbsp; &nbsp; &nbsp; &nbsp; -- &nbsp; -) ORA-02291: integrity constraint violated - parent key not found<br />&nbsp; &nbsp; &nbsp; &nbsp; -- &nbsp; -) ORA-02292: integrity constraint violated - child record found<br />&nbsp; &nbsp; &nbsp; &nbsp; --<br />&nbsp; &nbsp; &nbsp; &nbsp; -- we try to get a friendly error message from our constraint lookup configuration.<br />&nbsp; &nbsp; &nbsp; &nbsp; -- If we don't find the constraint in our lookup table we fallback to<br />&nbsp; &nbsp; &nbsp; &nbsp; -- the original ORA error message.<br />&nbsp; &nbsp; &nbsp; &nbsp; if p_error.ora_sqlcode in (-1, -2091, -2290, -2291, -2292) then<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; l_constraint_name := apex_error.extract_constraint_name (<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;p_error =&gt; p_error );<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; begin<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; select message<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; into l_result.message<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; from eba_proj_error_lookup<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;where constraint_name = l_constraint_name;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; exception when no_data_found then null; -- not every constraint has to be in our lookup table<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end;<br />&nbsp; &nbsp; &nbsp; &nbsp; end if;<br />&nbsp; &nbsp; &nbsp; &nbsp; -- If an ORA error has been raised, for example a raise_application_error(-20xxx)<br />&nbsp; &nbsp; &nbsp; &nbsp; -- in a table trigger or in a PL/SQL package called by a process and we<br />&nbsp; &nbsp; &nbsp; &nbsp; -- haven't found the error in our lookup table, then we just want to see<br />&nbsp; &nbsp; &nbsp; &nbsp; -- the actual error text and not the full error stack<br />&nbsp; &nbsp; &nbsp; &nbsp; if p_error.ora_sqlcode is not null and l_result.message = p_error.message then<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; l_result.message := apex_error.get_first_ora_error_text (<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; p_error =&gt; p_error );<br />&nbsp; &nbsp; &nbsp; &nbsp; end if;<br />&nbsp; &nbsp; &nbsp; &nbsp; -- If no associated page item/tabular form column has been set, we can use<br />&nbsp; &nbsp; &nbsp; &nbsp; -- apex_error.auto_set_associated_item to automatically guess the affected<br />&nbsp; &nbsp; &nbsp; &nbsp; -- error field by examine the ORA error for constraint names or column names.<br />&nbsp; &nbsp; &nbsp; &nbsp; if l_result.page_item_name is null and l_result.column_alias is null then<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; apex_error.auto_set_associated_item (<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; p_error &nbsp; &nbsp; &nbsp; &nbsp;=&gt; p_error,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; p_error_result =&gt; l_result );<br />&nbsp; &nbsp; &nbsp; &nbsp; end if;<br />&nbsp; &nbsp; end if;<br />&nbsp; &nbsp; return l_result;<br />end apex_error_handling; </code></div><br />When defining this error handling function the error the user gets is more like a notification message and embedded in your app. You can also define a custom message, in the above package there's a lookup in an error_lookup table, but as it can't find the constraint name, it falls back to the normal message.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-JP2bON9ne20/WzeWrJXXnHI/AAAAAAAAJQI/mbWUkU1vZGgl-DefeXo5fecDrwo2vxQKQCEwYBhgL/s1600/error.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="240" data-original-width="1412" height="108" src="https://1.bp.blogspot.com/-JP2bON9ne20/WzeWrJXXnHI/AAAAAAAAJQI/mbWUkU1vZGgl-DefeXo5fecDrwo2vxQKQCEwYBhgL/s640/error.png" width="640" /></a></div><br />The real power comes when you start to combine the error handling function with a call to also <b>log session state information</b>. Then you know exactly which record this error was produced for.<br /><br />There are a couple of ways to include the session state:<br /><br /><b>Team Development</b><br /><br />I typically include a feedback page in my apps. When the user logs feedback by clicking on the feedback link, this is saved in Team Development. The really cool thing is that whenever feedback is logged, automatically the session state of items and some other info like the browser that was being used at the moment of the logging is included. But you can also log feedback through an <a href="https://docs.oracle.com/database/apex-18.1/AEAPI/SUBMIT_FEEDBACK-Procedure.htm#AEAPI516">APEX API</a>:<br /><br /><code>apex_util.submit_feedback (<br />&nbsp; &nbsp; p_comment &nbsp; &nbsp; &nbsp; &nbsp; =&gt; 'Unexpected Error',<br />&nbsp; &nbsp; p_type &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;=&gt; 3,<br />&nbsp; &nbsp; p_application_id &nbsp;=&gt; v('APP_ID'),<br />&nbsp; &nbsp; p_page_id &nbsp; &nbsp; &nbsp; &nbsp; =&gt; v('APP_PAGE_ID'),<br />&nbsp; &nbsp; p_email &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =&gt; v('APP_USER'),<br />&nbsp; &nbsp; p_label_01 &nbsp; &nbsp; &nbsp; &nbsp;=&gt; 'Session',<br />&nbsp; &nbsp; p_attribute_01 &nbsp; &nbsp;=&gt; v('APP_SESSION'),<br />&nbsp; &nbsp; p_label_02 &nbsp; &nbsp; &nbsp; &nbsp;=&gt; 'Language',<br />&nbsp; &nbsp; p_attribute_02 &nbsp; &nbsp;=&gt; v('AI_LANGUAGE'),<br />&nbsp; &nbsp; p_label_03 &nbsp; &nbsp; &nbsp; &nbsp;=&gt; 'Error orq_sqlcode',<br />&nbsp; &nbsp; p_attribute_03 &nbsp; &nbsp;=&gt; p_error.ora_sqlcode,<br />&nbsp; &nbsp; p_label_04 &nbsp; &nbsp; &nbsp; &nbsp;=&gt; 'Error message',<br />&nbsp; &nbsp; p_attribute_04 &nbsp; &nbsp;=&gt; p_error.message,<br />&nbsp; &nbsp; p_label_05 &nbsp; &nbsp; &nbsp; &nbsp;=&gt; 'UI Error message',<br />&nbsp; &nbsp; p_attribute_05 &nbsp; &nbsp;=&gt; l_result.message<br />);</code><br /><br /><b><a href="https://github.com/OraOpenSource/Logger">Logger</a>&nbsp;</b><br /><br />Logger is a PL/SQL logging and debugging framework. If you don't know it yet, you should definitely check it out. In my opinion, Logger is the best way to instrument your PL/SQL code. Logger has many <a href="https://github.com/OraOpenSource/Logger/blob/master/docs/Logger%20API.md">cool features</a>, one of them is the ability to log your APEX items:<br /><code><br />logger.log_apex_items('Debug Items from Error log');<br /></code> With the above methods, you know which record the end-user was looking at and what the context was. Note that you might find this information too if you look at their session, but it would take more time to figure things out.<br /><br /><b>Be pro-active</b><br /><br />Now, to prevent the conversation from happening again, you can take it one step further and start logging and monitoring those errors. Whenever errors happen you can, for example, log it in your own error table, or in your support ticket system and send yourself an email or notification.<br />Then instead of the end-user calling you, you call them and say "Hey, I saw you had some issues...".<br /><br />By monitoring errors in your application, you can pro-actively take actions :)<br /><br />Note that APEX itself also stores Application Errors. You find under <b>Monitor Activity &gt; Application Errors</b>:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-5M9leBJw_Xk/Wzfsz70ZNbI/AAAAAAAAJQw/OVIIY_L-804iGrbzMi7BfJnY-Mt4QVkjwCLcBGAs/s1600/Screen%2BShot%2B2018-06-30%2Bat%2B22.48.44.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1288" data-original-width="1600" height="514" src="https://1.bp.blogspot.com/-5M9leBJw_Xk/Wzfsz70ZNbI/AAAAAAAAJQw/OVIIY_L-804iGrbzMi7BfJnY-Mt4QVkjwCLcBGAs/s640/Screen%2BShot%2B2018-06-30%2Bat%2B22.48.44.png" width="640" /></a></div><br />The report gives the error and the session, so you look further into what happened:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-47o8kaDIL6Y/WzftHerRUYI/AAAAAAAAJQ4/xZl7RMqWihMQwditc4Gdj5Nk5gjkPp4lQCLcBGAs/s1600/Screen%2BShot%2B2018-06-30%2Bat%2B22.49.35.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="642" data-original-width="1600" height="256" src="https://3.bp.blogspot.com/-47o8kaDIL6Y/WzftHerRUYI/AAAAAAAAJQ4/xZl7RMqWihMQwditc4Gdj5Nk5gjkPp4lQCLcBGAs/s640/Screen%2BShot%2B2018-06-30%2Bat%2B22.49.35.png" width="640" /></a></div><br />So, even when you didn't have an error handling function in place, you can still start monitoring errors that happen in your app. I know the readers of this blog are really smart so you might not see any errors, but still, it might be worthwhile to check it once and a while :)<br /><br />You find another example of the error handling function in my <a href="https://gist.github.com/dgielis/050d3f2169a44afc39514171f6b6095a">Git account</a>. I included an example of logging in your own error table and sending an email.<br /><br /><style>.gist .blob-wrapper.data { max-height:200px; overflow:auto; } </style><script src="https://gist.github.com/dgielis/050d3f2169a44afc39514171f6b6095a.js"></script> Dimitri Gielis tag:blogger.com,1999:blog-21122514.post-1829093026971429552 Sat Jun 30 2018 17:30:00 GMT-0400 (EDT) How to Export to Excel and Print to PDF in Oracle APEX? The answer... http://dgielis.blogspot.com/2018/06/how-to-export-to-excel-and-print-to-pdf.html Two questions that pop-up a lot when I'm at a conference or when doing consulting are:<br /><ul><li>How can I export my data from APEX to Excel?</li><li>How can I print to PDF? Or how can I get a document/report with my data?</li></ul><div>The reason those questions are asked every time again&nbsp;is that although those features exist to a certain extent in APEX, what you actually want, is not shipped with Oracle Application Express (APEX), at least not yet in Oracle APEX 18.1 and before.</div><div><br /></div><div>Although the solution to both questions is the same, I'll go into more detail on the specific questions separately.<br /><br /></div><b><u>How can I export my data from APEX to Excel?</u></b><br /><br />People typically want to export data from a Classic Report, Interactive Report, Interactive Grid or a combination of those to Excel.<br /><br />What APEX provides out-of-the-box is the export to CSV format, which can be opened in Excel.<br /><br />The biggest issue with CSV is that it's not native Excel format. Depending on the settings of Excel (or better your OS globalization settings) the CSV will open incorrectly. Instead of different columns, you see one big line. You also get an annoying message that some functions will be lost as it's not a native Excel format.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-MLx4rpIaNr4/WzCK2y_rb6I/AAAAAAAAJM8/yHyk4lAG58ITAjMwbf2phia7DMEIIAjNgCLcBGAs/s1600/Screen%2BShot%2B2018-06-25%2Bat%2B08.24.39.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="387" data-original-width="1600" height="154" src="https://2.bp.blogspot.com/-MLx4rpIaNr4/WzCK2y_rb6I/AAAAAAAAJM8/yHyk4lAG58ITAjMwbf2phia7DMEIIAjNgCLcBGAs/s640/Screen%2BShot%2B2018-06-25%2Bat%2B08.24.39.png" width="640" /></a></div><br />You can customize&nbsp;the CSV separator, so the columns are recognized. But with a global application (users with different settings), it's still a pain. Maybe the biggest issue people have with CSV export is that it's just plain text, so the markup or customizations (sum, group by, ...) are lost.<br /><br />You can enable the CSV export in the attributes section of the respective components:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-H8VVieDo5zY/Wy-_rT7CeQI/AAAAAAAAJMw/N09B-f5-BvUqhbj3A8sNErT01EQ2ZBHLwCLcBGAs/s1600/Screen%2BShot%2B2018-06-24%2Bat%2B17.56.47.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="744" data-original-width="1592" height="298" src="https://4.bp.blogspot.com/-H8VVieDo5zY/Wy-_rT7CeQI/AAAAAAAAJMw/N09B-f5-BvUqhbj3A8sNErT01EQ2ZBHLwCLcBGAs/s640/Screen%2BShot%2B2018-06-24%2Bat%2B17.56.47.png" width="640" /></a></div><br />When you have BI Publisher (BIP) <a href="http://www.oracle.com/technetwork/testcontent/apexinst-prod-092813.html#t4">setup</a> and in APEX specified as Print Server, you have a few more options. In the Classic Report, you find it in the Printing section - there's an option for Excel. In the Interactive Report, there's an option for XLS, the Interactive Grid doesn't have an option.<br /><br />BI Publisher is expensive and comes with a big infrastructure and maintenance overhead, so this is not an option for many APEX people. But even the companies who have it, are looking at other solutions because although you get a native Excel file, it's cumbersome&nbsp;to use and BIP doesn't export your Interactive Report exactly as you see it on the screen with the customizations you did.<br /><br />So how to get around those issues then? There are some APEX plugins to export an Interactive Report and Grid as you see it on the screen. The <a href="https://apex.world/ords/f?p=100:710:1651046443852::::P710_PLG_ID:GPV_IR_TO_MSEXCEL">plugin</a> of Pavel is probably the most popular one.<br />If you need to export one IR/IG at a time to Excel in a pre-defined Excel file, this might be an option for you. If you want to use your own Excel template, the ability to export multiple IR/IG at the same time or want more flexibility all around, you want to read on...<br /><br /><b>The solution</b><br /><br /><a href="https://www.apexofficeprint.com/">APEX Office Print (AOP)</a>. The AOP plugin extends APEX so you can specify the Excel file you want to start from, your&nbsp;template, in combination with the different APEX reports (Classic Report, Interactive Report, Interactive Grid) and get the output in Excel (or other formats). AOP is really easy to use, yet flexible and full of features no other solution provides. I'll touch on three different aspects customers love.<br /><br /><b>Interactive Report/Grid to Excel with AOP - WYSIWYG (!)</b><br /><br />This feature is what customers love about AOP and something you won't find anywhere else. You can print one or more Interactive Reports and Grids directly to Excel, exactly as you see it on the screen. So if the end-user made a break, added some highlights or did some computations, it's all known by AOP. Even the Group by and Pivot are no problem. The implementation is super simple; in Excel, you can define your template; a title, a logo etc. Where you want to see the Interactive Report or Grid you specify {&amp;interactive_1}, {&amp;interactive_2} and for the Interactive Grid you specify {&amp;static_id&amp;}. In the AOP APEX plugin, you specify the template, and the static ids of the Interactive Report / Grid regions and that is it! AOP is doing the merge... if in the template the special tags are seen, AOP will generate the IR/IG. Not a screenshot - REAL table data! Here's an example with one Interactive Report:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-6csgAiJWB2c/WzPrTitos6I/AAAAAAAAJNU/hUujiPxPeDovWvBNneZH_rnNQ1VrYOUDACLcBGAs/s1600/aop_interactive_reports_to_excel.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1194" data-original-width="1600" height="476" src="https://2.bp.blogspot.com/-6csgAiJWB2c/WzPrTitos6I/AAAAAAAAJNU/hUujiPxPeDovWvBNneZH_rnNQ1VrYOUDACLcBGAs/s640/aop_interactive_reports_to_excel.png" width="640" /></a></div><br />In your Excel you can add multiple tags, on the same sheet and on different sheets... and this doesn't only work in Excel, but also in Word and PDF!<br /><br />But there is even more... what if you look at the Interactive Report as a chart?<br />You got it... AOP even understands this. You can plot the table data with {&amp;interactive} and by using {$interactive} it will generate the chart ... and that is a native Office chart, you can still change it in Excel!<br /><br />Here's an example of the output generated by AOP with three interactive reports, one as a chart:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-IhiKG1MP9fc/WzPuyF3tHyI/AAAAAAAAJNg/Xw5B-UNlffUldzB7KudgqNGVAW1lU5BqQCLcBGAs/s1600/multiple_irs_with_chart.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="888" data-original-width="1600" height="354" src="https://4.bp.blogspot.com/-IhiKG1MP9fc/WzPuyF3tHyI/AAAAAAAAJNg/Xw5B-UNlffUldzB7KudgqNGVAW1lU5BqQCLcBGAs/s640/multiple_irs_with_chart.png" width="640" /></a></div><br />All the above goodies you can do through the AOP PL/SQL API too. Some people use this to schedule their reports and email them out on a daily basis, so they don't even have to go into APEX.<br /><br />For me, the Interactive Report and Grid feature are one of the killer features of&nbsp;AOP.<br /><br /><b>Advanced templates in Excel with AOP</b><br /><br />AOP is really flexible in how you build your template. The templating engine supports hierarchical data, angular expressions, conditions, blocks of data so you can view data next to each other and it supports HTML expressions too.<br /><br />Here's an example of a template which loops over the orders and shows the product of that order. It contains a condition to show an "X" when the quantity is higher than 2 and it also has an expression to calculate the price of the line (unit price * quantity).<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-nCWNYOQlx4o/WzP1wqxxONI/AAAAAAAAJNs/EftZY8M0eY4E3OLFp0a1TiY2VLaUtpxsQCLcBGAs/s1600/aop_excel_template.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="718" data-original-width="1600" height="286" src="https://2.bp.blogspot.com/-nCWNYOQlx4o/WzP1wqxxONI/AAAAAAAAJNs/EftZY8M0eY4E3OLFp0a1TiY2VLaUtpxsQCLcBGAs/s640/aop_excel_template.png" width="640" /></a></div><br />The data source specified in the plugin is of type SQL. AOP supports the cursor technique in SQL to create hierarchical data:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-WxmoUWNkCtY/WzP1wqO5kHI/AAAAAAAAJOA/VyPMbNnaPoMiJkoJhXQFQ5HWNNs9epLzwCEwYBhgL/s1600/aop_excel_source.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="980" data-original-width="1412" height="444" src="https://4.bp.blogspot.com/-WxmoUWNkCtY/WzP1wqO5kHI/AAAAAAAAJOA/VyPMbNnaPoMiJkoJhXQFQ5HWNNs9epLzwCEwYBhgL/s640/aop_excel_source.png" width="640" /></a></div><br />And (a part of) the output looks like this:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-pb5na78Gpw4/WzP1wi0GoaI/AAAAAAAAJN8/WPtQmyYt4hkDZ8cnTvmoQRRgj3rA6RfmACEwYBhgL/s1600/aop_excel_output.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="926" data-original-width="1502" height="394" src="https://2.bp.blogspot.com/-pb5na78Gpw4/WzP1wi0GoaI/AAAAAAAAJN8/WPtQmyYt4hkDZ8cnTvmoQRRgj3rA6RfmACEwYBhgL/s640/aop_excel_output.png" width="640" /></a></div><br /><div>I'm amazed by what people come up with in their templates to create really advanced Excel sheets. It's really up to your imagination... and a combination of the features of Excel.</div><div><br /></div><b>Multiple sheets in one Excel file with AOP</b><br /><br />We have one customer who basically dumps their entire database in Excel. Every table has its own sheet in Excel. You just need to put the right tags in the different sheets and you are done.<br /><br />AOP also supports the dynamic generation of sheets in Excel, so you get for example one sheet per customer and on that sheet the orders of that customer. The template looks like this (the magic tag is {!customers}):<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-rF_wVPADeXg/WzP3tteaw9I/AAAAAAAAJOI/9yctjxw4v3EYHF5CE8E1WkIgHjTwvJKGACLcBGAs/s1600/aop_dynamic_sheet_generation.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="465" data-original-width="1600" height="184" src="https://3.bp.blogspot.com/-rF_wVPADeXg/WzP3tteaw9I/AAAAAAAAJOI/9yctjxw4v3EYHF5CE8E1WkIgHjTwvJKGACLcBGAs/s640/aop_dynamic_sheet_generation.png" width="640" /></a></div><br />The output is this:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-rGcxQoS8Tx0/WzP4Xk_IbaI/AAAAAAAAJOQ/eVTzS7ZkVdkxIQAt9SPbAqRdw8-b1L1vACLcBGAs/s1600/aop_dynamic_sheet_generation_output.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="495" data-original-width="1600" height="198" src="https://3.bp.blogspot.com/-rGcxQoS8Tx0/WzP4Xk_IbaI/AAAAAAAAJOQ/eVTzS7ZkVdkxIQAt9SPbAqRdw8-b1L1vACLcBGAs/s640/aop_dynamic_sheet_generation_output.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div>We built this feature a while back based on some customers feedback.<br /><br /><b>Dynamic column generation in Excel with AOP</b><br /><br />This is a new feature we have been working for in AOP 4.0. By using the {:tag} we can generate columns dynamically now too:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-StpQKOgA5-w/WzP41oQAyHI/AAAAAAAAJOc/9sXL41zljP0TxiW02yLBMbl-Ad7zyngoACLcBGAs/s1600/aop_dynamic_generate_column.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="393" data-original-width="1600" height="156" src="https://3.bp.blogspot.com/-StpQKOgA5-w/WzP41oQAyHI/AAAAAAAAJOc/9sXL41zljP0TxiW02yLBMbl-Ad7zyngoACLcBGAs/s640/aop_dynamic_generate_column.png" width="640" /></a></div><br />This might be useful if you want to pivot the data or want to see it in a different format. This feature is also available for Word tables. Another way of pivoting is doing it in Oracle or in an Interactive Report. This feature took us a long time to develop, but we think it's worth it.<br /><br />I hope by the above I demonstrated why I believe <a href="https://www.apexofficeprint.com/">APEX Office Print</a> (AOP) is "THE" solution if you want to export your data from APEX (or the Oracle Database) into Excel.<br /><br /><br />Let's move on to the second question...<br /><br /><b><u>How can I print to PDF? Or how can I get a document/report with my data?</u></b><br /><br />Oracle Application Express (APEX) has two integrated ways to print to PDF: either you use XSL-FO or you use BI Publisher. But the reason people still ask the question of how to print to PDF is that the one is&nbsp;too hard to implement (XSL-FO) and the other (BI Publisher) is&nbsp;too expensive, too hard to maintain and not user-friendly enough.<br /><br />Again <a href="https://www.apexofficeprint.com/">APEX Office Print (AOP)</a> is the way to go. AOP is so easy to use, so well integrated with APEX, that most developers love to work with it. Based on a template you create in Word, Excel, Powerpoint, HTML or Text you can output to PDF. In combination with the AOP plugin or PL/SQL API, it's easy to define where your data and template is, and AOP does the merge for you.<br /><br /><b>Building the template</b><br /><br />It begins the same as with any print engine... You don't want to learn a new tool to build your template in. You want to have a fast result. So the way you get there with AOP is, use the AOP plugin, define your data source and let AOP generate the template for you. AOP will look at your data and create a starter template for you (in Word, Excel, HTML or Text) with the tags you can use based on your data and some explanation how to use the tags.<br /><br />Here's an example where AOP generates a Word template based on the SQL Query specified in the Data Source:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-LQ7BlycaCYo/WzVQibskB2I/AAAAAAAAJO0/nBfMMTKD_ZUyIjsv4BgrhoxqDOh9RgoVQCLcBGAs/s1600/aop_template.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1206" data-original-width="1600" height="482" src="https://4.bp.blogspot.com/-LQ7BlycaCYo/WzVQibskB2I/AAAAAAAAJO0/nBfMMTKD_ZUyIjsv4BgrhoxqDOh9RgoVQCLcBGAs/s640/aop_template.png" width="640" /></a></div><br /><br />So now you have a template you can start from. Next, you customize the template to your needs... or you can even let the business user customize the template. The only thing to know is how to use the specific {tags}. As a developer, I always thought my time would be better spent than changing the logo on a template or changing some sentences over and over again. With AOP my dream comes true; as a developer, I can concentrate on my query (data), the business user can create the template themselves and send the new version or upload it straight into the app whenever changes are required.<br /><br />When customers show me what they did with AOP; from creating templates for invoices, bills of materials, certificates to full-blown books, I'm really impressed by their creativity. If you imagine it, you can probably do it :)<br /><br />Here's the AOP plugin, where we specify where the customized Word template can be found (in Static Application Files) and set the output to PDF:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-2SLpXc2sjdA/WzVUKN3BTiI/AAAAAAAAJPA/HgOo6TzHJZo3qwoT2oXi5D1tBLIp16RXwCLcBGAs/s1600/aop_customised.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1199" data-original-width="1600" height="478" src="https://1.bp.blogspot.com/-2SLpXc2sjdA/WzVUKN3BTiI/AAAAAAAAJPA/HgOo6TzHJZo3qwoT2oXi5D1tBLIp16RXwCLcBGAs/s640/aop_customised.png" width="640" /></a></div><br /><b>Features in AOP that people love</b><br /><br />When you download <a href="https://www.apexofficeprint.com/">APEX Office Print</a>, it comes with a Sample app, which shows the features of AOP in action. Here's a screenshot of some of the Examples you find in the AOP Sample App:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-DDmm0ajrvkI/WzVXcGqLmVI/AAAAAAAAJPM/D43UONgTHhM38mKwcMVWI9yBz874321mQCLcBGAs/s1600/aop_sample_app.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1031" data-original-width="1600" height="412" src="https://1.bp.blogspot.com/-DDmm0ajrvkI/WzVXcGqLmVI/AAAAAAAAJPM/D43UONgTHhM38mKwcMVWI9yBz874321mQCLcBGAs/s640/aop_sample_app.png" width="640" /></a></div><br />As this blog post is getting long, I won't highlight all the features of AOP and why they rock so much, but I do want to take two features you probably won't find anywhere else.<br /><br /><b>Native Office Charts and JET Charts in PDF</b><br /><br />AOP supports the creation of native Office Charts, so you can even customize the charts further in Word. But sometimes people want to see exactly the chart they have on the screen, it is a JET chart, a Fusion chart, Highchart or any other library... With AOP you can get those charts straight into your PDF! The only thing you have to do&nbsp;is specifying the static id of the region and in your template, you put {%region} ... AOP will screenshot what the user sees and replace the tag with a sharp image. So even when the customer removed a series from the legend, it's exactly like that in the PDF.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-foqdsLx7wXA/WzVaGgaq8zI/AAAAAAAAJPY/hMJ3ULgQfYAA45ZgqWHWfGiuXs8TH36owCLcBGAs/s1600/Screen%2BShot%2B2018-06-28%2Bat%2B23.58.28.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="788" data-original-width="1600" height="314" src="https://2.bp.blogspot.com/-foqdsLx7wXA/WzVaGgaq8zI/AAAAAAAAJPY/hMJ3ULgQfYAA45ZgqWHWfGiuXs8TH36owCLcBGAs/s640/Screen%2BShot%2B2018-06-28%2Bat%2B23.58.28.png" width="640" /></a></div><br /><br /><b>HTML content in PDF</b><br /><br />At the <a href="https://www.nloug.nl/page.aspx?lang=en&amp;event=405">APEX World</a> conference, a customer showed their use case of APEX together with AOP. Before they had to manage different Word documents and PDFs, but it was so hard as they had to update different documents every time again, it got out of sync and it was just a pain overall to deal with. So they replaced all this by <a href="https://apex.oracle.com/">Oracle APEX</a> and Rich Text Editors. They created a structured database, so the information was in there once, but by using <a href="https://www.apexofficeprint.com/">APEX Office Print (AOP)</a> they generate all the different documents (Word/PDF) they need.<br /><br />AOP will interpret the HTML when it sees an underscore in the tag e.g. {_tag}, then it will translate that HTML into native Word styling. If a PDF is requested, the Word is converted to PDF, so the PDF contains real bold text, or real colors etc.<br /><br />Here's an example of how Rich Text is rendered to PDF.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-KZ5PB-eNPCs/WzVb-G-3OQI/AAAAAAAAJPk/jvWrwulpJuYrx3_wVuXFGv55JseunncRQCLcBGAs/s1600/Screen%2BShot%2B2018-06-29%2Bat%2B00.06.25.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1185" data-original-width="1600" height="472" src="https://2.bp.blogspot.com/-KZ5PB-eNPCs/WzVb-G-3OQI/AAAAAAAAJPk/jvWrwulpJuYrx3_wVuXFGv55JseunncRQCLcBGAs/s640/Screen%2BShot%2B2018-06-29%2Bat%2B00.06.25.png" width="640" /></a></div><br />AOP also understands when you use for example HTML expressions in your Classic or Interactive Report, or you do some inline styling. It took us a very long time to develop this feature, but the feedback we get from our customer base made it worthwhile :)<br /><br />So far I showed Word as starting template for your PDF, but sometimes Powerpoint is a great start too, and not many people know about that. In Powerpoint you can make pixel perfect templates too and go to PDF is as easy as coming from Word.<br /><br />In our upcoming release of AOP 4.0, we spend a lot of time improving our PDF feature set. We will introduce PDF split and merge and the ability to prepend and append files to any of your documents.<br /><br /><br /><b>Some last words</b><br /><br />If you are interested in what <a href="https://www.apexofficeprint.com/">APEX Office Print (AOP)</a> is all about, I recommend to sit down and watch this 45 minutes video I did at the <a href="https://apex.doag.org/de/archiv-2018/">APEX Connect</a> conference. In that presentation, I go from downloading, installing to using and show many features of AOP live.<br /><br /><iframe allow="autoplay; encrypted-media" allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/vpfVotHmIcw" width="560"></iframe><br /><br />We at <a href="https://www.apexrnd.be/">APEX R&amp;D</a> are committed to bringing the best possible print engine to APEX, which makes your life easier. We find it important to listen to you and support you however we can. We really want you to be successful. So if you have feedback for us in ways we can help you, even more, let us know, we care about you. We won't rest before we let everybody know about our mission and want to stay "the" printing solution for APEX.<br /><br />Sometimes I get emails from developers who tell me they have to do a comparison between the print engines for Oracle APEX, but they love AOP. If you include some of the above features (IR/IG to PDF or Excel, JET Charts, and HTML to PDF) in your requirements, you are guaranteed to work with <a href="https://www.apexofficeprint.com/">APEX Office Print</a>, there's nothing else that comes even close to those features :)<br /><br />AOP's philosophy has been to be as integrated as possible in APEX, as easy as building APEX applications, yet flexible enough to build really advanced reports. We make printing and exporting of data in APEX easy.<br /><br />If you read until here, you are amazing, now I rest my case :) Dimitri Gielis tag:blogger.com,1999:blog-21122514.post-7465278930775684814 Thu Jun 28 2018 17:46:00 GMT-0400 (EDT) dbms_scheduler 12c – run EXTERNAL_SCRIPT https://svenweller.wordpress.com/2018/06/28/dbms_scheduler-12c-run-external_script/ <h2>Introduction</h2> <p>With 12c we have several new job types for our scheduler jobs. One of them is EXTERNAL_SCRIPT. The other new job types are SQL_SCRIPT and BACKUP_SCRIPT.</p> <p>From <a href="https://docs.oracle.com/en/database/oracle/oracle-database/12.2/arpls/DBMS_SCHEDULER.html#GUID-7E744D62-13F6-40E9-91F0-1569E6C38BBC" target="_blank" rel="noopener">Oracle 12.2 plsql packages and type reference</a></p> <blockquote><p>&#8216;EXTERNAL_SCRIPT&#8217;</p> <p>This specifies that the job is an external script that uses the command shell of the computer running the job. For Windows this is cmd.exe and for UNIX based systems the sh shell, unless a different interpreter is specified by prefixing the first line of the script with #!.</p></blockquote> <p>In the past we could run an external script using the EXECUTABLE job type. This type is still available.</p> <blockquote><p>&#8216;EXECUTABLE&#8217;</p> <p>This specifies that the job is going to be run outside the database using an external executable. External jobs are anything that can be executed from the command line of the operating system. Anydata arguments are not supported with a job or program type of EXECUTABLE. The job owner must have the CREATE EXTERNAL JOB system privilege before the job can be enabled or run.</p></blockquote> <p>In general both options could do the same thing. Execute something on the host OS.<br /> So why should we change anything? Is there a difference?</p> <p>Let&#8217;s find out.</p> <h2>schedule an EXTERNAL_SCRIPT</h2> <h3>setup credentials first</h3> <p>We can create credentials using a dbms package or via SQL Developer.</p> <pre class="brush: sql; light: true; title: ; notranslate"> dbms_credential.create_credential(credential_name =&gt; 'ORACLE_OS_CREDS', username =&gt; 'oracle', password =&gt; 'oracle', comments =&gt; 'run scripts using oracle OS account'); </pre> <p>In the developer VM box, the password is always oracle. That&#8217;s why I included it here. You need to use your own correct password.</p> <p>For real world environments I suggest to create a specific OS account that is only allowed to execute the script and to do anything that needs to be done for this specific task but not more. This account might need the &#8220;Log On As Batch Job&#8221; Right under windows (support note <a href="https://support.oracle.com/epmos/faces/DocumentDisplay?id=2065024.1" target="_blank" rel="noopener">#2065024.1</a>).</p> <p>For demonstration purposes I stay here with the oracle credentials.</p> <h3>setup a scheduled job to run a linux script</h3> <p>Of cause this works under windows too, but I did test it only using Oracle Linux.</p> <p>Here I setup 4 slightly different examples how to run an EXTERNAL_SCRIPT job. After that we check and compare the output.</p> <p>These are our for slightly different test scenarios.</p> <ol> <li>run a simple bash script.</li> <li>run a script, that has an error</li> <li>run a script with an error, but an exitcode=0</li> <li>same as 3. and use undocumented FAIL_ON_SCRIPT_ERROR argument</li> </ol> <p>To test what happens if the script itself has an error, I added a change directory command pointing to a non existent directory.<br /> This command will result in an error.</p> <pre>cd /abcd/efgh/ijk</pre> <p>Here is the command to schedule the 4 jobs. Each job has a slightly different name. The differences between one and the previous job are marked.</p> <pre class="brush: sql; highlight: [11,36,60,94,95,96,97,98]; title: ; notranslate"> -- First test a script that does not produce an error declare v_jobname varchar2(200); v_good_script clob; begin v_jobname := upper('DEMO_SCHEDULED_EXTERNAL_SCRIPT_NO_ERROR'); -- the following line breaks are important. -- Do NOT remove them, they are part of the linux script. v_good_script := '#!/bin/bash echo "Job ok!"'; dbms_scheduler.create_job(job_name =&gt; v_jobname, job_type =&gt; 'EXTERNAL_SCRIPT', job_action =&gt; v_good_script, credential_name =&gt; 'ORACLE_OS_CREDS', enabled =&gt; false, auto_drop =&gt; false ); -- run the job dbms_scheduler.enable(v_jobname); end; / PL/SQL procedure successfully completed. -- Now test a script that does produce an error declare v_jobname varchar2(200); v_bad_script clob; begin v_jobname := upper('DEMO_SCHEDULED_EXTERNAL_SCRIPT_WITH_ERROR'); v_bad_script := '#!/bin/bash cd /abcd/efgh/ijk'; dbms_scheduler.create_job(job_name =&gt; v_jobname, job_type =&gt; 'EXTERNAL_SCRIPT', job_action =&gt; v_bad_script, credential_name =&gt; 'ORACLE_OS_CREDS', enabled =&gt; false, auto_drop =&gt; false ); dbms_scheduler.enable(v_jobname); end; / PL/SQL procedure successfully completed. -- Now test a script that does produce an error but uses exit 0 declare v_jobname varchar2(200); v_bad_script clob; begin v_jobname := upper('DEMO_SCHEDULED_EXTERNAL_SCRIPT_WITH_ERROR_EXIT0'); v_bad_script := '#!/bin/bash cd /abcd/efgh/ijk exit 0'; dbms_scheduler.create_job(job_name =&gt; v_jobname, job_type =&gt; 'EXTERNAL_SCRIPT', job_action =&gt; v_bad_script, credential_name =&gt; 'ORACLE_OS_CREDS', enabled =&gt; false, auto_drop =&gt; false ); dbms_scheduler.enable(v_jobname); end; / PL/SQL procedure successfully completed. -- run script using attribute FAIL_ON_ERROR declare v_jobname varchar2(200); v_bad_script clob; begin v_jobname := upper('DEMO_SCHEDULED_EXTERNAL_SCRIPT_WITH_ERROR_FAILONERROR'); v_bad_script := '#!/bin/bash cd /abcd/efgh/ijk exit 0'; dbms_scheduler.create_job(job_name =&gt; v_jobname, job_type =&gt; 'EXTERNAL_SCRIPT', job_action =&gt; v_bad_script, credential_name =&gt; 'ORACLE_OS_CREDS', enabled =&gt; false, auto_drop =&gt; false ); -- Make sure script errors result in a job error and are noticed. dbms_scheduler.set_attribute( name =&gt; v_jobname, attribute =&gt; 'FAIL_ON_SCRIPT_ERROR', value =&gt; true); -- run the job dbms_scheduler.enable(v_jobname); end; / PL/SQL procedure successfully completed. </pre> <p>Note that all anonymous blocks executed successfully. This only means that we could create and start a scheduled job. It does not tell us, what the result of the job was.</p> <p>To find the job result, we need to check the data dictionary view all_scheduler_job_run_details. The information is in there but only AFTER the job finished.</p> <h3>Results</h3> <p>The data dictionary gives us information about the result of the scheduler runs in the view ALL_SCHEDULER_JOB_RUN_DETAILS.</p> <pre class="brush: sql; title: ; notranslate"> select replace(job_name,'DEMO_SCHEDULED_EXTERNAL_SCRIPT') as job_name, log_date, status, output, error#, errors, additional_info from all_Scheduler_job_run_details where job_name like 'DEMO_SCHEDULED_EXTERNAL_SCRIPT%' --and log_date &gt;= sysdate - interval '5' minute; </pre> <p>For presentation purposes I flipped rows and columns. So the next picture shows the columns from the DD view as rows.<br /> <img data-attachment-id="7794" data-permalink="https://svenweller.wordpress.com/2018/06/28/dbms_scheduler-12c-run-external_script/result_run_details_transposed/" data-orig-file="https://svenweller.files.wordpress.com/2018/06/result_run_details_transposed.png?w=809" data-orig-size="1081,281" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="result_run_details_transposed" data-image-description="" data-medium-file="https://svenweller.files.wordpress.com/2018/06/result_run_details_transposed.png?w=809?w=300" data-large-file="https://svenweller.files.wordpress.com/2018/06/result_run_details_transposed.png?w=809?w=809" src="https://svenweller.files.wordpress.com/2018/06/result_run_details_transposed.png?w=809" alt="result_run_details_transposed" class="alignnone size-full wp-image-7794" srcset="https://svenweller.files.wordpress.com/2018/06/result_run_details_transposed.png?w=809 809w, https://svenweller.files.wordpress.com/2018/06/result_run_details_transposed.png?w=150 150w, https://svenweller.files.wordpress.com/2018/06/result_run_details_transposed.png?w=300 300w, https://svenweller.files.wordpress.com/2018/06/result_run_details_transposed.png?w=768 768w, https://svenweller.files.wordpress.com/2018/06/result_run_details_transposed.png?w=1024 1024w, https://svenweller.files.wordpress.com/2018/06/result_run_details_transposed.png 1081w" sizes="(max-width: 809px) 100vw, 809px" /></p> <p>Let&#8217;s go through the results step by step.</p> <p>The first testcase did not have an error. <strong>status</strong> of the run = SUCCEEDED. The <strong>output</strong> column also shows the stdev output which is nice. So there is no need to spool the output into an extra file, just to be able to see later what happend. The same column is also used for jobs of type SQL_SCRIPT to return dbms_output.<br />  <br /> The second testcase had an error. The job status correctly reported that the script errored with exit code = 1 (column <strong>error#</strong>). And we see what kind of error happen in the <strong>errors </strong>column. </p> <pre>"/tmp/job_2078996_3568888_script: line 2: cd: /abcd/efgh/ijk: No such file or directory "</pre> <p> We also see that the script itself was created as a file in the /tmp folder using job and log id for the file name &#8220;job_2078996_3568888_script&#8221;.<br /> Also note that the <strong>additional_info</strong> column says </p> <pre>"EXTERNAL_LOG_ID="job_2078995_3568886", ORA-27369: job of type EXECUTABLE failed with exit code: Operation not permitted "</pre> <p>This is slightly misleading, since the <strong>job_type</strong> was EXTERNAL_SCRIPT and not EXECUTABLE. And &#8220;Operation not permitted&#8221; could lead us suspecting some issue with privs (might be the case when &#8220;cd&#8221; doesn&#8217;t work) or with the credentials (definitly not the case here).</p> <p>The third testcase had an error in the script, however it finished with exit 0 (=success). It makes sense that in this case the job run <strong>status</strong> is also marked as SUCCEEDED. However the error &#8220;no such file or directory&#8221; still can be found in the <strong>errors</strong> column.</p> <p>The forth testcase uses a new feature. I&#8217;m not sure if that is already there in the 12.1 db version, all my tests were done under 12.2. The all_scheduler_jobs view has a new column <strong>FAIL_ON_SCRIPT_ERROR</strong>. It defaults to FALSE. We can set this as an attribute for the scheduled job. </p> <pre class="brush: sql; title: ; notranslate"> dbms_scheduler.set_attribute( name =&gt; v_jobname, attribute =&gt; 'FAIL_ON_SCRIPT_ERROR', value =&gt; true); </pre> <p>This is currently undocumented, but it works, as above demo shows. I believe it is a documentation bug. The new column in the view is documented, but FAIL_ON_SCRIPT_ERROR is not in the <a href="https://docs.oracle.com/en/database/oracle/oracle-database/12.2/arpls/DBMS_SCHEDULER.html#GUID-D7A11F8A-8746-4815-91C4-BC8DDBA4C74A" target="_blank">list of allowed attributes</a>.</p> <p>The result is, that even with EXIT=0, the job status goes to FAILED. We also see a different error number 27382 instead of 1. 27382 seems to be the ORA-Error number that we also see in the <strong>additional_details</strong> column. This column now says &#8220;ORA-27382: job type EXTERNAL_SCRIPT has errors in the job action&#8221;. Not a major difference, but slightly better additional_details when we use this attribute. </p> <p>Quite some interesting behaviour. So if we want to run a script that always exits with 0, we can still make our job go to FAILED if there are any errors inside that script.</p> <p>I would guess that we find the same behaviour for the other new job_types SQL_SCRIPT and BACKUP_SCRIPT. I didn&#8217;t test it yet.</p> <h2>Comparison between EXTERNAL_SCRIPT and EXECUTABLE</h2> <p>Executable is the old way.</p> <p>It requires to configure and start an external agent. Often this is a fairly complex task. It involves configuration of the listener, tnsnames.ora, extproc.ora and some other parts. Those are usually not under control of a developer. Additionally all external jobs that are executed using this agent run with the same OS privileges. Using credentials gives us a little more control.</p> <p>Starting from 12.1 such external jobs can alternativly run with credentials. Same as I already showed for running external_scripts. So the credentials argument is only a half-baked one.</p> <p>It is also difficult to track down an error in case something goes wrong. This is where EXTERNAL_SCRIPT seem much better then EXECUTABLE. I have to admit I did only some very short tests about this, but I never found a disadvantage for running a scheduled job as EXTERNAL_SCRIPT instead of EXECUTABLE.</p> <p>So if you have a choice go with the newer option.</p> <h2>Integrate it into plsql including status check</h2> <p>How to setup a plsql procedure that is able to run an external_script, but also returns an exception, in case the script runs into errors?</p> <p>Lets assume the external script is something like this:</p> <pre># set environment export PATH=/usr/local/bin:$PATH export ORACLE_SID=XE export ORAENV_ASK=NO . /usr/local/bin/oraenv CLASSPATH=fonts #CLASSPATH=$CLASSPATH:$APEX_HOME/utilities CLASSPATH=$CLASSPATH:. export CLASSPATH cd /opt/jasper/report1 java -jar runJasperReport.jar exit </pre> <p>So this executes some jar file. I don&#8217;t want to wait until the java logic is finished, but I want to be informed if something basic goes wrong, like if the jar file couldn&#8217;t be found.</p> <p>Here is an example that I used in some APEX application. After the job is started, it hangs around for a couple of seconds and checks if anything surprising did happen. The code to start the job itself is not included. But you can assume that it is done in the same packaged procedure. The script is in the v_script variable.</p> <p>Do not copy it 1:1, but understand it and adapt it to your needs.</p> <pre class="brush: sql; title: ; notranslate"> ... v_jobname varchar2(128); r_job_details all_scheduler_job_run_details%rowtype; r_job all_scheduler_jobs%rowtype; c_max_check_job_tries constant binary_integer :=3; v_message varchar2(1000); v_script clob; begin ... -- check if the scheduled job did sucessfully start. -- In case some error happend after starting the job, we might not notice that, since it was started in the background. -- e.G. ORA-27369: Job of Typ EXECUTABLE not successfull with Exit-Code: No such file or directory -- In such a case check scheduler data dictionary almost immediatly after job creation. apex_util.pause(p_seconds =&gt; 0.5); &lt;&gt; for i in 1..c_max_check_job_tries loop -- constant is set to 3, so max. wait time = 3.5 seconds. -- read info about scheduled job -- started/running jobs are in scheduler_jobs, fnished jobs including results are in scheduler_job_run_details begin select * into r_job from all_scheduler_jobs where job_name = upper(v_jobname); logger.trace(p_message=&gt;'Job "'||v_jobname||'" created with state='||r_job.state ); exception when no_data_found then -- Job might have stopped already, check run details! r_job.state := 'NOT FOUND'; end; if r_job.state in ('RUNNING','SCHEDULED') then -- RUNNING+SCHEDULED =&gt; Looks ok, Job runs,just to make sure wait for another few seconds apex_util.pause(p_seconds =&gt; 1); else begin -- for any other state check details select * into r_job_details from all_scheduler_job_run_details where job_name = upper(v_jobname); logger.trace(p_message=&gt;'Job Details "'||v_jobname||'" with status='||r_job_details.status ); if r_job_details.status= 'FAILED' or r_job.state= 'FAILED' then v_message := 'Job "'|| v_jobname||'" with Error!'; if r_job_details.additional_info like '%ORA-27369%' or r_job_details.additional_info like '%ORA-27382%' then v_message := v_message ||' Jobaction='||v_script; end if; pk_logging.pr_logError(p_message=&gt;v_message); apex_error.add_error( p_message =&gt; v_message, p_additional_info =&gt; r_job_details.additional_info, p_display_location =&gt; apex_error.c_inline_in_notification --apex_error.c_on_error_page ); -- step out of loop and raise an error using the OS error message Raise_application_error(-20001, r_job_details.errors); end if; exception when no_data_found then -- Job not started yet or just about to finish... -- consider to wait a few sec first. Then raise an error if job still not there. -- last try? if i=c_max_check_job_tries then logger.error(p_message=&gt;'Job "'||v_jobname||'" was not started!'); Raise_application_error(-20001, 'Warning! Job "'|| v_jobname||'" wasn't started (yet)! Check application log!'); else -- wait 1 second until job is hopefully created apex_util.pause(p_seconds =&gt; 1); end if; end; end if; end loop get_job_info; if r_job.state = 'SCHEDULED' then -- still scheduled? inform user Raise_application_error(-20001, 'Warning! Job "'|| v_jobname||'" needs longer than expected to start. Please monitor closely and informa administrator!'); end if; ... </pre> <h2>Security considerations</h2> <p>Running external jobs is always something where we need to take extra care &#8211; so that we do not put holes into our security defense system.</p> <p>I carefully watch out for two major security risks:<br /> 1) If we add something dynamically to the script that we are executing, like an extra parameter, make sure to sanitize all the inputs. Otherwise we could get some kind of injection problem.</p> <p>2) The agent/account that runs our script should only get the least needed privileges. So it shoud NOT be running under user oracle, like I did in the demo.<br /> Create a separate account for that. Name the account to something that logically points to the task that it is supposed to do.</p> <h2>conclusion</h2> <p><strong>The new job_type EXECUTE_SCRIPT is useful. </strong></p> <p>Some of the hurdles that developers face when trying to run a host command are lowered. The script itself does not need to be deployed on the database server.</p> <p>Reacting to errors in the script is possible, but we need to check the correct columns and use the proper settings.</p> <h3>cleanup demo jobs</h3> <pre class="brush: sql; title: ; notranslate"> -- cleanup -- remove all the jobs execute dbms_scheduler.drop_job(job_name =&gt; 'DEMO_SCHEDULED_EXTERNAL_SCRIPT_NO_ERROR'); execute dbms_scheduler.drop_job(job_name =&gt; 'DEMO_SCHEDULED_EXTERNAL_SCRIPT_WITH_ERROR'); execute dbms_scheduler.drop_job(job_name =&gt; 'DEMO_SCHEDULED_EXTERNAL_SCRIPT_WITH_ERROR_EXIT0'); execute dbms_scheduler.drop_job(job_name =&gt; 'DEMO_SCHEDULED_EXTERNAL_SCRIPT_WITH_ERROR_FAILONERROR'); </pre> svenweller http://svenweller.wordpress.com/?p=7789 Thu Jun 28 2018 11:13:41 GMT-0400 (EDT) Enable save button on form change https://www.apex-at-work.com/2018/06/enable-save-button-on-form-change.html Today I had the requirement that the save button should stay disabled until a form item changed.<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-SQgHsL-ESZg/WzTzy_iLRyI/AAAAAAAAB94/GKsstzHC70wRFB_LpwIW7OXI-d5UfMEZQCLcBGAs/s1600/Rechnungsempfa%25CC%2588nger_bearbeiten.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="52" data-original-width="260" src="https://1.bp.blogspot.com/-SQgHsL-ESZg/WzTzy_iLRyI/AAAAAAAAB94/GKsstzHC70wRFB_LpwIW7OXI-d5UfMEZQCLcBGAs/s1600/Rechnungsempfa%25CC%2588nger_bearbeiten.png" /></a></div><br />After digging around I found a quite easy solution which worked well until now.<br /><br /><b>Save Button</b><br />Static ID: saveBtn<br />Custom Attributes: disabled<br /><br /><b>Dynamic Action</b><br />Event: Page Load<br />Execute Javascript Code:<br /><span style="font-family: &quot;Courier New&quot;, Courier, monospace;">$('#wwvFlowForm').on('input change', function() {<br />&nbsp;&nbsp;&nbsp; $('#saveBtn').attr('disabled', false);<br />});</span><br /><br /><br />Simple but effective. Tobias Arnhold tag:blogger.com,1999:blog-6481483192141562388.post-6461028354276635706 Thu Jun 28 2018 10:42:00 GMT-0400 (EDT) APEX 18.1: No need for configuration tables any more http://apexbyg.blogspot.com/2018/06/apex-181-no-need-for-configuration.html <div dir="ltr" style="text-align: left;" trbidi="on">There's probably no application that doesn't need some kind of configuration table for storing different data across different environments (development/test/production) - like URL to the report server, configuration parameters and stuff like that.<br /><br />Before APEX 18.1 in most cases I would create some simple key-value configuration table, set procedure and get function...repeating same task over and over again.<br /><br />From APEX 18.1 you don't have to do that anymore. There's new feature called Application Settings.<br /><br />There are two ways to manage Application Settings. One is from the Application Builder (Shared Components):<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-Yo1Sr7WVrKA/WzPfqTz2krI/AAAAAAAAE8U/FZGwxqjFU2UQfOtFv478UpNUbjJn78WYgCLcBGAs/s1600/Screen%2BShot%2B2018-06-27%2Bat%2B21.03.07.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="479" data-original-width="800" height="383" src="https://4.bp.blogspot.com/-Yo1Sr7WVrKA/WzPfqTz2krI/AAAAAAAAE8U/FZGwxqjFU2UQfOtFv478UpNUbjJn78WYgCLcBGAs/s640/Screen%2BShot%2B2018-06-27%2Bat%2B21.03.07.png" width="640" /></a></div><br />You can define several properties there, but the one I like the most is <i>On Upgrade Keep Value</i>. If set to <i>Yes</i> it will keep the setting value upon application upgrade. That means that you can export your application from the development environment and import it to the other environments without any worries that parameter values will be overridden.<br /><br />There's also API to control those parameters from PL/SQL. There's new package apex_app_setting with set_value procedure and get_value function. For more info see <a href="https://docs.oracle.com/database/apex-18.1/AEAPI/APEX_APP_SETTING.htm#AEAPI-GUID-22D1A770-2748-42CB-A679-F89CD33B1335" target="_blank">documentation</a>.<br /><br />Enjoy!<br /><br /></div> Marko Gorički tag:blogger.com,1999:blog-1003209687173038896.post-4468082016698210391 Wed Jun 27 2018 15:30:00 GMT-0400 (EDT) Working with the APEX tree https://www.apex-at-work.com/2018/06/working-with-apex-tree.html Out of a coincidence I haven't used the APEX tree region for years. Now I got the task to create a customizable tree in my application. Since APEX 5 there is a new tree type called "APEX tree" which supports some really cool functions.<br /><br />Anyway I had to look around to find out what the APEX tree is actually capable of. First of all start with the APEX "Sample Trees" application which you find in the packaged application area.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-ARPF5w-7g4Q/WzNh_abbjsI/AAAAAAAAB9s/jM2WMYH6_WI1ypyR0nU6K-jkHIQ7I-91QCLcBGAs/s1600/Packaged_Application_Details.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="159" data-original-width="441" height="115" src="https://2.bp.blogspot.com/-ARPF5w-7g4Q/WzNh_abbjsI/AAAAAAAAB9s/jM2WMYH6_WI1ypyR0nU6K-jkHIQ7I-91QCLcBGAs/s320/Packaged_Application_Details.png" width="320" /></a></div><br /><br />Morten Braten took that example and described the features really well:<br /><a href="https://ora-00001.blogspot.com/2016/01/working-with-the-apex-5-treeview.html" target="_blank">https://ora-00001.blogspot.com/2016/01/working-with-the-apex-5-treeview.html</a><br /><br />John Snyders from the APEX team also created 2 blogposts about the "APEX tree":<br /><a href="http://hardlikesoftware.com/weblog/2015/05/01/apex-5-0-converting-to-the-new-apex-tree/" target="_blank">APEX 5.0 Converting to the new APEX Tree</a><br /><a href="http://hardlikesoftware.com/weblog/2017/04/12/add-checkbox-selection-to-apex-tree-region/" target="_blank">Add Checkbox Selection to APEX Tree Region</a><br /><br />And as he mentioned there is a Javascript library behind it "<code>libraries/apex/widget.treeView.js</code>." which is documented since APEX 18.1 or at least I think it is. Anyway here is a link which I also have to further investigate:<br /><a href="https://apex.oracle.com/pls/apex/apex_pm/r/520052/files/static/v56/jsdoc/treeView.html" target="_blank">JS Doc: Widget: treeView</a><br /><br />German users can read this document provided by MT AG:<br /><a href="http://files.xmasman.de/20160216_MeetupNRW_TillAlbert_WiePflanzeIchEinenBaumApex.pdf">http://files.xmasman.de/20160216_MeetupNRW_TillAlbert_WiePflanzeIchEinenBaumApex.pdf</a> Tobias Arnhold tag:blogger.com,1999:blog-6481483192141562388.post-695830597719725206 Wed Jun 27 2018 06:19:00 GMT-0400 (EDT) How to Avoid a JavaScript Mess http://vmorneau.me/avoid-javascript-mess/ <div class="kg-post"> <blockquote> <img src="https://images.unsplash.com/photo-1515524738708-327f6b0037a7?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ&s=33dc33ce5706917521381c7d810b42c2" alt="How to Avoid a JavaScript Mess"><p>At Kscope18, I presented <strong>How to Avoid a JavaScript Mess</strong> at the <a href="http://dietmaraust.com/odtug-kscope18-deep-dive-javascript-in-apex-do-it-the-right-way">#LetsWreckThisTogether talks</a>. Here it is, turned into a blog post.</p> </blockquote> <p><strong>We all want to write clean code.</strong></p> <p>I was attending Mike Hichwa's session at Kscope18's Sunday symposium, and he revealed numbers about language usage within the frameworks we use.</p> <p>APEX is made up of over a million lines of JS.<br> ORDS contains over 300 000 lines of JS.</p> <p>And I keep hearing we shouldn't do JavaScript in APEX. That sounds counter intuitive to me. <mark>So instead of hiding from JavaScript, maybe we should just embrace it.</mark></p> <p>But when you start doing more JavaScript, it is easy to fall into the culprits of the language. One important challenge you'll face when developing a large scale application, is keeping your client-side codebase from becoming a huge mess.</p> <p>The 4 tips below are my kick-start for a cleaner JavaScript usage in APEX.</p> <hr> <h2 id="tip1keepitoutofapex">Tip #1: Keep It Out of APEX</h2> <p>In all my years of APEX development, I found that APEX is best used when the least amount of code is stored in the application itself.</p> <p>It's common practice to wrap PL/SQL code in packages and SQL into views. Once we have all that business logic in the database, all APEX should be doing is referencing those objects. It's easier to manage and it's easier to version control.</p> <p>For some reason, when writing JavaScript, developers tend to forget these good intentions and good practices.</p> <p>One lazy excuse I hear too often is:</p> <blockquote> <p>I just have to write a single line of JavaScript, so it’s not worth the hassle of creating a file for it.</p> </blockquote> <p>Let's be real, that's never the case. My point is: <mark>there should not be a single line of JavaScript business logic within APEX.</mark> Only invoke functions from external files.</p> <figure class="kg-image-card"><img src="http://vmorneau.me/content/images/2018/06/avoid-js-mess-1-1.png" class="kg-image" alt="How to Avoid a JavaScript Mess"><figcaption>Wrong usage of JavaScript in APEX</figcaption></figure><p>Let’s look at the above. Observations:</p> <ol> <li>We have a simple button</li> <li>It has a dynamic action attached to its onClick event</li> <li>Dynamic Action triggers an action of type: Execute JavaScript code</li> </ol> <p>So we might be tempted to put the JavaScript logic on the righthand side, but that’s wrong!</p> <p>Instead, what we want is moving business logic JavaScript code into a file, and wrap it inside of a function, like the following top level function named <code>registerKscope()</code></p> <figure class="kg-image-card"><img src="http://vmorneau.me/content/images/2018/06/image-3.png" class="kg-image" alt="How to Avoid a JavaScript Mess"><figcaption>Moving the JavaScript code to a file</figcaption></figure><p>Then, in page designer we can invoke function <code>registerKscope()</code>.</p> <figure class="kg-image-card"><img src="http://vmorneau.me/content/images/2018/06/image-4.png" class="kg-image" alt="How to Avoid a JavaScript Mess"><figcaption>Better usage of JavaScript in APEX</figcaption></figure><blockquote> <p><strong>TLDR:</strong></p> <ul> <li>APEX is best used when the least amount of code is stored in the application</li> <li>We constantly wrap PL/SQL into packages and SQL into views. JavaScript can do it too.</li> <li>Lazy excuse: &quot;I only have to write one line of JavaScript&quot;</li> <li>APEX should only invoke JavaScript functions coming from external files</li> </ul> </blockquote> <h2 id="tip2modularizeyourjavascript">Tip #2: Modularize your JavaScript</h2> <p>What's the purpose of a PL/SQL package? Giving context to a function or a procedure. So when invoking a PL/SQL API, we would use <code>&lt;package_name&gt;.&lt;procedure_name&gt;</code>.</p> <p><mark>Similarly, JavaScript can be modularized with <strong>namespaces</strong>, and it can even go deeper than two levels.</mark> The whole APEX JavaScript API is built like this. Example:</p> <pre><code class="language-javascript">/** * @namespace odtug **/ var odtug = odtug || {}; /** * @module kscope18 **/ odtug.kscope18 = { /** * @function register * @example odtug.kscope18.register(); **/ register: function () { // Insert JavaScript here } }; </code></pre> <p>Having such a structure in your functions makes your files MUCH cleaner.</p> <figure class="kg-image-card"><img src="http://vmorneau.me/content/images/2018/06/image-5.png" class="kg-image" alt="How to Avoid a JavaScript Mess"><figcaption>Best usage of JavaScript in APEX</figcaption></figure><p>If you are building a large scale application, a great pattern would be to have one JavaScript file per APEX page, each file representing a JavaScript module for your application. Example: <code>myApp.p1.doSomething();</code> and <code>myApp.p2.doSomethingElse();</code></p> <blockquote> <p><strong>TLDR:</strong></p> <ul> <li>A <strong>namespace</strong> gives context to JavaScript functions, similarly to PL/SQL packages</li> <li>Namespaces allow building JavaScript APIs with more than two levels (Example: <code>apex.server.process</code>)</li> <li>Makes files much cleaner</li> <li>Pattern idea: one JavaScript module per APEX page (Example: <code>myApp.p1.doSomething();</code> and <code>myApp.p2.doSomethingElse();</code>)</li> </ul> </blockquote> <h2 id="tip3useamoderncodeeditor">Tip #3: Use a Modern Code Editor</h2> <p>There are so many good code editors today. I think it's fair to say that the most popular ones are (in no particular order)</p> <ul> <li><a href="https://code.visualstudio.com/">VS Code</a> <em>(I'm using this one)</em></li> <li><a href="https://atom.io/">Atom</a></li> <li><a href="https://www.sublimetext.com/">Sublime</a></li> </ul> <p>Why would you want to use them? Here's an important rundown:</p> <ul> <li><strong>IntelliSense</strong>: is a term referring to a variety of code features like code completion and parameter information.</li> <li><strong>Multi-cursor editing</strong>: Why make one change at a time when you can make ten? This feature alone should be enough to persuade you to switch.</li> </ul> <figure class="kg-image-card"><img src="http://vmorneau.me/content/images/2018/06/avoid-js-mess-multi-cursor.gif" class="kg-image" alt="How to Avoid a JavaScript Mess"><figcaption>Multi-cursor editing in VS Codepl</figcaption></figure><ul> <li><strong>Plugins</strong>: These editors have rich plugin ecosystems. The editor's out-of-the-box features are just the start. Plugins let you add new languages, code linters, text transformations and way more. Anything you can think of applying to your code, there’s a plugin for that.</li> <li><strong>Command palette</strong>: Being efficient at keyboard shortcuts is important, but if you can just remember the shortcut for the command palette, then you have every possible action at your fingertips, through a searchable list popup.</li> </ul> <figure class="kg-image-card"><img src="http://vmorneau.me/content/images/2018/06/image-6.png" class="kg-image" alt="How to Avoid a JavaScript Mess"><figcaption>VS Code when invoking the command pallette</figcaption></figure><ul> <li><strong>Snippets</strong>: Some of them are built in, like JavaScript's <code>forEach</code> or otherwise you can add your own APEX Snippets (<code>apex.server.process</code>)</li> </ul> <figure class="kg-image-card"><img src="http://vmorneau.me/content/images/2018/06/avoid-js-mess-snippets.gif" class="kg-image" alt="How to Avoid a JavaScript Mess"></figure><p><mark>Non-JavaScript bonus feature: it compiles against the Oracle database too!</mark> Thanks to a <a href="https://marketplace.visualstudio.com/items?itemName=tschf.odb-task">plugin</a> by <a href="https://twitter.com/trentschafer">Trent Schafer</a></p> <p>Being comfortable with a new code editor does take time, but don't be discouraged by the first few days. The productivity benefits are worth it.</p> <blockquote> <p><strong>TLDR:</strong></p> <ul> <li>IntelliSense: JavaScript code completion</li> <li>They've got a plugin for everything</li> <li>Command palette: one shortcut to access all available actions</li> <li>Baked with premade JavaScript code snippets (<code>if</code> statement, <code>loop</code> statement, etc.)</li> <li>Custom code snippets (your own snippets, APEX snippets perhaps?)</li> </ul> </blockquote> <h2 id="tip4useastylelinter">Tip #4: Use a Style Linter</h2> <p>JavaScript is the perfect language to give up your personal coding style habits. A style linter is a tool that reads your file and detects coding style anomalies.</p> <p>I am using <a href="https://github.com/xojs/xo">XO</a>, and it mercilessly tells me where my coding style is inconsistent. <mark>We should not spend <strong>any time</strong> developing and maintaining our own coding style. Let's hand that over to linters.</mark></p> <p>To use XO in my project directory, I would simply do:</p> <pre><code class="language-bash">xo </code></pre> <figure class="kg-image-card"><img src="http://vmorneau.me/content/images/2018/06/image-7.png" class="kg-image" alt="How to Avoid a JavaScript Mess"><figcaption>XO making coding style recommendations</figcaption></figure><p>Or even better, if I want XO to fix my code automatically, I can do:</p> <pre><code class="language-bash">xo --fix </code></pre> <hr><p>Needless to say, there is more to writing clean code than these 4 tips, so this blog post is subject to be updated in the future.</p><p><em>Have any insights for writing cleaner JavaScript in APEX? Let me know in the comments.</em></p><p></p><p></p> </div> Vincent Morneau 5b2c5d892b634e341cd41276 Tue Jun 26 2018 19:37:27 GMT-0400 (EDT) AUSOUG APEX webinar series 2018 http://lschilde.blogspot.com/2018/06/ausoug-apex-webinar-series-2018-great.html <div dir="ltr" style="text-align: left;" trbidi="on"><h2 class="MsoNormal" style="line-height: normal; text-align: justify;"><b><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;; font-size: 18.0pt;"><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;"><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;"><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;"><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;"><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;"><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;">AUSOUG</span> APEX webinar series 2018 </span></span></span></span></span></span></b></h2><h2 class="MsoNormal" style="line-height: normal; text-align: justify;"></h2><h3 class="MsoNormal" style="line-height: normal; text-align: left;"><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;"><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;"><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;"><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;"><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;">&nbsp;</span></span></span></span></span></h3><h3 class="MsoNormal" style="line-height: normal; text-align: left;"><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;"><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;"><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;"><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;"><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;"><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;">Great speakers<span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;">,</span> great content!</span></span></span></span><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;">&nbsp;</span> </span></span></h3><h3 class="MsoNormal" style="line-height: normal; text-align: left;"></h3><h4 class="MsoNormal" style="line-height: normal; text-align: left;"><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;">&nbsp;</span></h4><h4 class="MsoNormal" style="line-height: normal; text-align: left;"><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;"><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;">Running from mid July to late October 2018</span><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;"><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;"><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;"><span style="font-family: &quot;arial&quot; , &quot;sans-serif&quot;;"></span></span></span></span></span></h4><div style="text-align: justify;"><br /><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif; font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">T</span>ogether </span><span style="font-size: small;">with AUSOUG and awesome APEX community </span><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-size: small;">I am glad to announce <a href="http://www.ausoug.org.au/" target="_blank"><b>A</b></a></span><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-size: small;"><a href="http://www.ausoug.org.au/pages/page?x1=apexwebinars2018" target="_blank"><b>PEX 2018 webinar series</b></a></span><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">.</span></span></span></span></span><br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="http://4.bp.blogspot.com/-eswF2xoyrJw/WzHSqlJOQiI/AAAAAAAAMHM/TvusuU53Qn4vdMnRHKP1KQpV6QXIaD6dQCK4BGAYYCw/s1600/apeks.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="120" src="https://4.bp.blogspot.com/-eswF2xoyrJw/WzHSqlJOQiI/AAAAAAAAMHM/TvusuU53Qn4vdMnRHKP1KQpV6QXIaD6dQCK4BGAYYCw/s320/apeks.png" width="320" /></a></div><br /><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">A<span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">s</span> <span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">Oracle APEX fans we gather to learn together and from each other.</span>&nbsp;</span></span><br /><br /><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">This year we will have PL/SQL and APE<span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">X sessions t<span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">oo.&nbsp;</span></span></span> </span></span></div><br /><div style="text-align: justify;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><b><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-size: large;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">Amazing sessions and speakers</span></span></span></span></span></span></span></span></span></span></b></span></div><ul style="text-align: left;"><li><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><b><span style="line-height: 115%;">Connor McDonald</span></b><span style="line-height: 115%;"> Oracle Developer Advocate @ORACLE, Australia</span></span></span></li><li><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><b><span style="line-height: 115%;">John Watson</span></b><span style="line-height: 115%;"> Oracle Certified Master @Skillbuilders, USA</span></span></span></li><li><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><b><span style="line-height: 115%;">Shakeeb Rahman</span></b><span style="line-height: 115%;"> Design Lead for APEX @Oracle, USA</span></span></span></li><li><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><b><span style="line-height: 150%;">Dimitri Gielis</span></b><span style="line-height: 150%;"> Oracle ACE director and founder of AOP and APEXR&amp;D, Belgium</span></span></span></li><li><!--[if gte mso 9]><xml> <w:WordDocument> <w:View>Normal</w:View> <w:Zoom>0</w:Zoom> <w:TrackMoves/> <w:TrackFormatting/> <w:PunctuationKerning/> <w:ValidateAgainstSchemas/> <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid> <w:IgnoreMixedContent>false</w:IgnoreMixedContent> <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText> <w:DoNotPromoteQF/> <w:LidThemeOther>EN-AU</w:LidThemeOther> <w:LidThemeAsian>X-NONE</w:LidThemeAsian> <w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript> <w:Compatibility> <w:BreakWrappedTables/> <w:SnapToGridInCell/> <w:WrapTextWithPunct/> <w:UseAsianBreakRules/> <w:DontGrowAutofit/> <w:SplitPgBreakAndParaMark/> <w:EnableOpenTypeKerning/> <w:DontFlipMirrorIndents/> <w:OverrideTableStyleHps/> </w:Compatibility> <m:mathPr> <m:mathFont m:val="Cambria Math"/> <m:brkBin m:val="before"/> <m:brkBinSub m:val="&#45;-"/> <m:smallFrac m:val="off"/> <m:dispDef/> <m:lMargin m:val="0"/> <m:rMargin m:val="0"/> <m:defJc m:val="centerGroup"/> <m:wrapIndent m:val="1440"/> <m:intLim m:val="subSup"/> <m:naryLim m:val="undOvr"/> </m:mathPr></w:WordDocument></xml><![endif]--><!--[if gte mso 9]><xml> <w:LatentStyles DefLockedState="false" DefUnhideWhenUsed="true" DefSemiHidden="true" DefQFormat="false" DefPriority="99" LatentStyleCount="267"> <w:LsdException Locked="false" Priority="0" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Normal"/> <w:LsdException Locked="false" Priority="9" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="heading 1"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 2"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 3"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 4"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 5"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 6"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 7"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 8"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 9"/> <w:LsdException Locked="false" Priority="39" Name="toc 1"/> <w:LsdException Locked="false" Priority="39" Name="toc 2"/> <w:LsdException Locked="false" Priority="39" Name="toc 3"/> <w:LsdException Locked="false" Priority="39" Name="toc 4"/> <w:LsdException Locked="false" Priority="39" Name="toc 5"/> <w:LsdException Locked="false" Priority="39" Name="toc 6"/> <w:LsdException Locked="false" Priority="39" Name="toc 7"/> <w:LsdException Locked="false" Priority="39" Name="toc 8"/> <w:LsdException Locked="false" Priority="39" Name="toc 9"/> <w:LsdException Locked="false" Priority="35" QFormat="true" Name="caption"/> <w:LsdException Locked="false" Priority="10" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Title"/> <w:LsdException Locked="false" Priority="1" Name="Default Paragraph Font"/> <w:LsdException Locked="false" Priority="11" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtitle"/> <w:LsdException Locked="false" Priority="22" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Strong"/> <w:LsdException Locked="false" Priority="20" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Emphasis"/> <w:LsdException Locked="false" Priority="59" SemiHidden="false" UnhideWhenUsed="false" Name="Table Grid"/> <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Placeholder Text"/> <w:LsdException Locked="false" Priority="1" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="No Spacing"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 1"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 1"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 1"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 1"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 1"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 1"/> <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Revision"/> <w:LsdException Locked="false" Priority="34" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="List Paragraph"/> <w:LsdException Locked="false" Priority="29" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Quote"/> <w:LsdException Locked="false" Priority="30" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Quote"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 1"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 1"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 1"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 1"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 1"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 1"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 1"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 1"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 2"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 2"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 2"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 2"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 2"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 2"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 2"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 2"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 2"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 2"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 2"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 2"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 2"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 2"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 3"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 3"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 3"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 3"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 3"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 3"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 3"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 3"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 3"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 3"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 3"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 3"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 3"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 3"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 4"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 4"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 4"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 4"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 4"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 4"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 4"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 4"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 4"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 4"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 4"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 4"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 4"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 4"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 5"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 5"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 5"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 5"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 5"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 5"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 5"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 5"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 5"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 5"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 5"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 5"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 5"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 5"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 6"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 6"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 6"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 6"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 6"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 6"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 6"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 6"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 6"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 6"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 6"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 6"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 6"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 6"/> <w:LsdException Locked="false" Priority="19" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtle Emphasis"/> <w:LsdException Locked="false" Priority="21" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Emphasis"/> <w:LsdException Locked="false" Priority="31" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtle Reference"/> <w:LsdException Locked="false" Priority="32" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Reference"/> <w:LsdException Locked="false" Priority="33" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Book Title"/> <w:LsdException Locked="false" Priority="37" Name="Bibliography"/> <w:LsdException Locked="false" Priority="39" QFormat="true" Name="TOC Heading"/> </w:LatentStyles></xml><![endif]--><!--[if gte mso 10]><style> /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-priority:99; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin-top:0cm; mso-para-margin-right:0cm; mso-para-margin-bottom:10.0pt; mso-para-margin-left:0cm; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-fareast-language:EN-US;} </style><![endif]--><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><b><span style="line-height: 150%;">Scott Spendolini</span></b><span style="line-height: 150%;"> Oracle ACE director and Vice President of the APEX Practice @Viscosity North America</span></span></span></li><li><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="line-height: 150%;"><!--[if gte mso 9]><xml> <w:WordDocument> <w:View>Normal</w:View> <w:Zoom>0</w:Zoom> <w:TrackMoves/> <w:TrackFormatting/> <w:PunctuationKerning/> <w:ValidateAgainstSchemas/> <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid> <w:IgnoreMixedContent>false</w:IgnoreMixedContent> <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText> <w:DoNotPromoteQF/> <w:LidThemeOther>EN-AU</w:LidThemeOther> <w:LidThemeAsian>X-NONE</w:LidThemeAsian> <w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript> <w:Compatibility> <w:BreakWrappedTables/> <w:SnapToGridInCell/> <w:WrapTextWithPunct/> <w:UseAsianBreakRules/> <w:DontGrowAutofit/> <w:SplitPgBreakAndParaMark/> <w:EnableOpenTypeKerning/> <w:DontFlipMirrorIndents/> <w:OverrideTableStyleHps/> </w:Compatibility> <m:mathPr> <m:mathFont m:val="Cambria Math"/> <m:brkBin m:val="before"/> <m:brkBinSub m:val="&#45;-"/> <m:smallFrac m:val="off"/> <m:dispDef/> <m:lMargin m:val="0"/> <m:rMargin m:val="0"/> <m:defJc m:val="centerGroup"/> <m:wrapIndent m:val="1440"/> <m:intLim m:val="subSup"/> <m:naryLim m:val="undOvr"/> </m:mathPr></w:WordDocument></xml><![endif]--><!--[if gte mso 9]><xml> <w:LatentStyles DefLockedState="false" DefUnhideWhenUsed="true" DefSemiHidden="true" DefQFormat="false" DefPriority="99" LatentStyleCount="267"> <w:LsdException Locked="false" Priority="0" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Normal"/> <w:LsdException Locked="false" Priority="9" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="heading 1"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 2"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 3"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 4"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 5"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 6"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 7"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 8"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 9"/> <w:LsdException Locked="false" Priority="39" Name="toc 1"/> <w:LsdException Locked="false" Priority="39" Name="toc 2"/> <w:LsdException Locked="false" Priority="39" Name="toc 3"/> <w:LsdException Locked="false" Priority="39" Name="toc 4"/> <w:LsdException Locked="false" Priority="39" Name="toc 5"/> <w:LsdException Locked="false" Priority="39" Name="toc 6"/> <w:LsdException Locked="false" Priority="39" Name="toc 7"/> <w:LsdException Locked="false" Priority="39" Name="toc 8"/> <w:LsdException Locked="false" Priority="39" Name="toc 9"/> <w:LsdException Locked="false" Priority="35" QFormat="true" Name="caption"/> <w:LsdException Locked="false" Priority="10" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Title"/> <w:LsdException Locked="false" Priority="1" Name="Default Paragraph Font"/> <w:LsdException Locked="false" Priority="11" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtitle"/> <w:LsdException Locked="false" Priority="22" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Strong"/> <w:LsdException Locked="false" Priority="20" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Emphasis"/> <w:LsdException Locked="false" Priority="59" SemiHidden="false" UnhideWhenUsed="false" Name="Table Grid"/> <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Placeholder Text"/> <w:LsdException Locked="false" Priority="1" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="No Spacing"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 1"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 1"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 1"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 1"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 1"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 1"/> <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Revision"/> <w:LsdException Locked="false" Priority="34" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="List Paragraph"/> <w:LsdException Locked="false" Priority="29" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Quote"/> <w:LsdException Locked="false" Priority="30" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Quote"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 1"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 1"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 1"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 1"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 1"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 1"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 1"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 1"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 2"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 2"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 2"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 2"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 2"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 2"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 2"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 2"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 2"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 2"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 2"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 2"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 2"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 2"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 3"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 3"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 3"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 3"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 3"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 3"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 3"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 3"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 3"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 3"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 3"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 3"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 3"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 3"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 4"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 4"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 4"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 4"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 4"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 4"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 4"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 4"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 4"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 4"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 4"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 4"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 4"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 4"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 5"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 5"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 5"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 5"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 5"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 5"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 5"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 5"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 5"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 5"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 5"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 5"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 5"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 5"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 6"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 6"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 6"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 6"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 6"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 6"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 6"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 6"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 6"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 6"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 6"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 6"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 6"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 6"/> <w:LsdException Locked="false" Priority="19" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtle Emphasis"/> <w:LsdException Locked="false" Priority="21" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Emphasis"/> <w:LsdException Locked="false" Priority="31" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtle Reference"/> <w:LsdException Locked="false" Priority="32" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Reference"/> <w:LsdException Locked="false" Priority="33" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Book Title"/> <w:LsdException Locked="false" Priority="37" Name="Bibliography"/> <w:LsdException Locked="false" Priority="39" QFormat="true" Name="TOC Heading"/> </w:LatentStyles></xml><![endif]--><!--[if gte mso 10]><style> /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-priority:99; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin-top:0cm; mso-para-margin-right:0cm; mso-para-margin-bottom:10.0pt; mso-para-margin-left:0cm; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-fareast-language:EN-US;} </style><![endif]--><b><span style="line-height: 115%;">Niels de Bruijn</span></b><span style="line-height: 115%;"> Oracle ACE director @MT AG, Germany</span><b><span style="line-height: 115%;">&nbsp;</span></b></span></span></span></li><li><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="line-height: 150%;"><b><span style="line-height: 115%;">Jackie Mcllroy</span></b><span style="line-height: 115%;"> Senior APEX developer @INSUM,USA</span>&nbsp;</span></span></span></li><li><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><b><span style="line-height: 150%;">Menno Hoogendijk</span></b><span style="line-height: 150%;"> Oracle ACE Associate @Qualogy, Netherlands</span></span></span></li><li><!--[if gte mso 9]><xml> <w:WordDocument> <w:View>Normal</w:View> <w:Zoom>0</w:Zoom> <w:TrackMoves/> <w:TrackFormatting/> <w:PunctuationKerning/> <w:ValidateAgainstSchemas/> <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid> <w:IgnoreMixedContent>false</w:IgnoreMixedContent> <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText> <w:DoNotPromoteQF/> <w:LidThemeOther>EN-AU</w:LidThemeOther> <w:LidThemeAsian>X-NONE</w:LidThemeAsian> <w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript> <w:Compatibility> <w:BreakWrappedTables/> <w:SnapToGridInCell/> <w:WrapTextWithPunct/> <w:UseAsianBreakRules/> <w:DontGrowAutofit/> <w:SplitPgBreakAndParaMark/> <w:EnableOpenTypeKerning/> <w:DontFlipMirrorIndents/> <w:OverrideTableStyleHps/> </w:Compatibility> <m:mathPr> <m:mathFont m:val="Cambria Math"/> <m:brkBin m:val="before"/> <m:brkBinSub m:val="&#45;-"/> <m:smallFrac m:val="off"/> <m:dispDef/> <m:lMargin m:val="0"/> <m:rMargin m:val="0"/> <m:defJc m:val="centerGroup"/> <m:wrapIndent m:val="1440"/> <m:intLim m:val="subSup"/> <m:naryLim m:val="undOvr"/> </m:mathPr></w:WordDocument></xml><![endif]--><!--[if gte mso 9]><xml> <w:LatentStyles DefLockedState="false" DefUnhideWhenUsed="true" DefSemiHidden="true" DefQFormat="false" DefPriority="99" LatentStyleCount="267"> <w:LsdException Locked="false" Priority="0" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Normal"/> <w:LsdException Locked="false" Priority="9" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="heading 1"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 2"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 3"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 4"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 5"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 6"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 7"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 8"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 9"/> <w:LsdException Locked="false" Priority="39" Name="toc 1"/> <w:LsdException Locked="false" Priority="39" Name="toc 2"/> <w:LsdException Locked="false" Priority="39" Name="toc 3"/> <w:LsdException Locked="false" Priority="39" Name="toc 4"/> <w:LsdException Locked="false" Priority="39" Name="toc 5"/> <w:LsdException Locked="false" Priority="39" Name="toc 6"/> <w:LsdException Locked="false" Priority="39" Name="toc 7"/> <w:LsdException Locked="false" Priority="39" Name="toc 8"/> <w:LsdException Locked="false" Priority="39" Name="toc 9"/> <w:LsdException Locked="false" Priority="35" QFormat="true" Name="caption"/> <w:LsdException Locked="false" Priority="10" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Title"/> <w:LsdException Locked="false" Priority="1" Name="Default Paragraph Font"/> <w:LsdException Locked="false" Priority="11" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtitle"/> <w:LsdException Locked="false" Priority="22" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Strong"/> <w:LsdException Locked="false" Priority="20" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Emphasis"/> <w:LsdException Locked="false" Priority="59" SemiHidden="false" UnhideWhenUsed="false" Name="Table Grid"/> <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Placeholder Text"/> <w:LsdException Locked="false" Priority="1" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="No Spacing"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 1"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 1"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 1"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 1"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 1"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 1"/> <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Revision"/> <w:LsdException Locked="false" Priority="34" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="List Paragraph"/> <w:LsdException Locked="false" Priority="29" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Quote"/> <w:LsdException Locked="false" Priority="30" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Quote"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 1"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 1"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 1"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 1"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 1"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 1"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 1"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 1"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 2"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 2"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 2"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 2"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 2"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 2"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 2"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 2"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 2"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 2"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 2"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 2"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 2"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 2"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 3"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 3"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 3"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 3"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 3"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 3"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 3"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 3"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 3"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 3"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 3"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 3"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 3"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 3"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 4"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 4"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 4"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 4"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 4"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 4"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 4"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 4"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 4"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 4"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 4"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 4"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 4"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 4"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 5"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 5"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 5"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 5"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 5"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 5"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 5"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 5"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 5"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 5"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 5"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 5"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 5"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 5"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 6"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 6"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 6"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 6"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 6"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 6"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 6"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 6"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 6"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 6"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 6"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 6"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 6"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 6"/> <w:LsdException Locked="false" Priority="19" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtle Emphasis"/> <w:LsdException Locked="false" Priority="21" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Emphasis"/> <w:LsdException Locked="false" Priority="31" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtle Reference"/> <w:LsdException Locked="false" Priority="32" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Reference"/> <w:LsdException Locked="false" Priority="33" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Book Title"/> <w:LsdException Locked="false" Priority="37" Name="Bibliography"/> <w:LsdException Locked="false" Priority="39" QFormat="true" Name="TOC Heading"/> </w:LatentStyles></xml><![endif]--><!--[if gte mso 10]><style> /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-priority:99; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin-top:0cm; mso-para-margin-right:0cm; mso-para-margin-bottom:10.0pt; mso-para-margin-left:0cm; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-fareast-language:EN-US;} </style><![endif]--><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><b><span style="line-height: 115%;">Tyson Jouglet</span></b><span style="line-height: 115%;"> APEX expert @Skillbuilders, USA</span></span></span></li><li><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><b><span style="line-height: 115%;">Maxime Tremblay</span></b><span style="line-height: 115%;"> apex.world Member of the Year 2016 @Momentum Technologies, Canada</span></span></span></li><li><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><b><span style="line-height: 115%;">Simon Hunt</span></b><span style="line-height: 115%;">, </span></span></span><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="line-height: 115%;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="line-height: 150%;">Oracle ACE Associate</span></span></span> @apextestautomation, UK</span></span></span></li><li><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="line-height: 115%;"><!--[if gte mso 9]><xml> <w:WordDocument> <w:View>Normal</w:View> <w:Zoom>0</w:Zoom> <w:TrackMoves/> <w:TrackFormatting/> <w:PunctuationKerning/> <w:ValidateAgainstSchemas/> <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid> <w:IgnoreMixedContent>false</w:IgnoreMixedContent> <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText> <w:DoNotPromoteQF/> <w:LidThemeOther>EN-AU</w:LidThemeOther> <w:LidThemeAsian>X-NONE</w:LidThemeAsian> <w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript> <w:Compatibility> <w:BreakWrappedTables/> <w:SnapToGridInCell/> <w:WrapTextWithPunct/> <w:UseAsianBreakRules/> <w:DontGrowAutofit/> <w:SplitPgBreakAndParaMark/> <w:EnableOpenTypeKerning/> <w:DontFlipMirrorIndents/> <w:OverrideTableStyleHps/> </w:Compatibility> <m:mathPr> <m:mathFont m:val="Cambria Math"/> <m:brkBin m:val="before"/> <m:brkBinSub m:val="&#45;-"/> <m:smallFrac m:val="off"/> <m:dispDef/> <m:lMargin m:val="0"/> <m:rMargin m:val="0"/> <m:defJc m:val="centerGroup"/> <m:wrapIndent m:val="1440"/> <m:intLim m:val="subSup"/> <m:naryLim m:val="undOvr"/> </m:mathPr></w:WordDocument></xml><![endif]--><!--[if gte mso 9]><xml> <w:LatentStyles DefLockedState="false" DefUnhideWhenUsed="true" DefSemiHidden="true" DefQFormat="false" DefPriority="99" LatentStyleCount="267"> <w:LsdException Locked="false" Priority="0" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Normal"/> <w:LsdException Locked="false" Priority="9" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="heading 1"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 2"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 3"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 4"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 5"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 6"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 7"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 8"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 9"/> <w:LsdException Locked="false" Priority="39" Name="toc 1"/> <w:LsdException Locked="false" Priority="39" Name="toc 2"/> <w:LsdException Locked="false" Priority="39" Name="toc 3"/> <w:LsdException Locked="false" Priority="39" Name="toc 4"/> <w:LsdException Locked="false" Priority="39" Name="toc 5"/> <w:LsdException Locked="false" Priority="39" Name="toc 6"/> <w:LsdException Locked="false" Priority="39" Name="toc 7"/> <w:LsdException Locked="false" Priority="39" Name="toc 8"/> <w:LsdException Locked="false" Priority="39" Name="toc 9"/> <w:LsdException Locked="false" Priority="35" QFormat="true" Name="caption"/> <w:LsdException Locked="false" Priority="10" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Title"/> <w:LsdException Locked="false" Priority="1" Name="Default Paragraph Font"/> <w:LsdException Locked="false" Priority="11" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtitle"/> <w:LsdException Locked="false" Priority="22" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Strong"/> <w:LsdException Locked="false" Priority="20" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Emphasis"/> <w:LsdException Locked="false" Priority="59" SemiHidden="false" UnhideWhenUsed="false" Name="Table Grid"/> <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Placeholder Text"/> <w:LsdException Locked="false" Priority="1" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="No Spacing"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 1"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 1"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 1"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 1"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 1"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 1"/> <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Revision"/> <w:LsdException Locked="false" Priority="34" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="List Paragraph"/> <w:LsdException Locked="false" Priority="29" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Quote"/> <w:LsdException Locked="false" Priority="30" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Quote"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 1"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 1"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 1"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 1"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 1"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 1"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 1"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 1"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 2"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 2"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 2"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 2"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 2"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 2"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 2"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 2"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 2"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 2"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 2"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 2"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 2"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 2"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 3"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 3"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 3"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 3"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 3"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 3"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 3"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 3"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 3"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 3"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 3"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 3"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 3"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 3"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 4"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 4"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 4"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 4"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 4"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 4"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 4"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 4"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 4"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 4"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 4"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 4"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 4"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 4"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 5"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 5"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 5"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 5"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 5"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 5"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 5"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 5"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 5"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 5"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 5"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 5"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 5"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 5"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 6"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 6"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 6"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 6"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 6"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 6"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 6"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 6"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 6"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 6"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 6"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 6"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 6"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 6"/> <w:LsdException Locked="false" Priority="19" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtle Emphasis"/> <w:LsdException Locked="false" Priority="21" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Emphasis"/> <w:LsdException Locked="false" Priority="31" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtle Reference"/> <w:LsdException Locked="false" Priority="32" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Reference"/> <w:LsdException Locked="false" Priority="33" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Book Title"/> <w:LsdException Locked="false" Priority="37" Name="Bibliography"/> <w:LsdException Locked="false" Priority="39" QFormat="true" Name="TOC Heading"/> </w:LatentStyles></xml><![endif]--><!--[if gte mso 10]><style> /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-priority:99; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin-top:0cm; mso-para-margin-right:0cm; mso-para-margin-bottom:10.0pt; mso-para-margin-left:0cm; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-fareast-language:EN-US;} </style><![endif]--><b><span style="line-height: 115%;">Aljaz Mali</span></b><span style="line-height: 115%;">, Oracle ACE Associate @Abakus Plus, Slovenia</span></span></span></span></li><li><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="line-height: 115%;"><span style="line-height: 115%;"><!--[if gte mso 9]><xml> <w:WordDocument> <w:View>Normal</w:View> <w:Zoom>0</w:Zoom> <w:TrackMoves/> <w:TrackFormatting/> <w:PunctuationKerning/> <w:ValidateAgainstSchemas/> <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid> <w:IgnoreMixedContent>false</w:IgnoreMixedContent> <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText> <w:DoNotPromoteQF/> <w:LidThemeOther>EN-AU</w:LidThemeOther> <w:LidThemeAsian>X-NONE</w:LidThemeAsian> <w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript> <w:Compatibility> <w:BreakWrappedTables/> <w:SnapToGridInCell/> <w:WrapTextWithPunct/> <w:UseAsianBreakRules/> <w:DontGrowAutofit/> <w:SplitPgBreakAndParaMark/> <w:EnableOpenTypeKerning/> <w:DontFlipMirrorIndents/> <w:OverrideTableStyleHps/> </w:Compatibility> <m:mathPr> <m:mathFont m:val="Cambria Math"/> <m:brkBin m:val="before"/> <m:brkBinSub m:val="&#45;-"/> <m:smallFrac m:val="off"/> <m:dispDef/> <m:lMargin m:val="0"/> <m:rMargin m:val="0"/> <m:defJc m:val="centerGroup"/> <m:wrapIndent m:val="1440"/> <m:intLim m:val="subSup"/> <m:naryLim m:val="undOvr"/> </m:mathPr></w:WordDocument></xml><![endif]--><!--[if gte mso 9]><xml> <w:LatentStyles DefLockedState="false" DefUnhideWhenUsed="true" DefSemiHidden="true" DefQFormat="false" DefPriority="99" LatentStyleCount="267"> <w:LsdException Locked="false" Priority="0" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Normal"/> <w:LsdException Locked="false" Priority="9" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="heading 1"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 2"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 3"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 4"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 5"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 6"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 7"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 8"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 9"/> <w:LsdException Locked="false" Priority="39" Name="toc 1"/> <w:LsdException Locked="false" Priority="39" Name="toc 2"/> <w:LsdException Locked="false" Priority="39" Name="toc 3"/> <w:LsdException Locked="false" Priority="39" Name="toc 4"/> <w:LsdException Locked="false" Priority="39" Name="toc 5"/> <w:LsdException Locked="false" Priority="39" Name="toc 6"/> <w:LsdException Locked="false" Priority="39" Name="toc 7"/> <w:LsdException Locked="false" Priority="39" Name="toc 8"/> <w:LsdException Locked="false" Priority="39" Name="toc 9"/> <w:LsdException Locked="false" Priority="35" QFormat="true" Name="caption"/> <w:LsdException Locked="false" Priority="10" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Title"/> <w:LsdException Locked="false" Priority="1" Name="Default Paragraph Font"/> <w:LsdException Locked="false" Priority="11" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtitle"/> <w:LsdException Locked="false" Priority="22" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Strong"/> <w:LsdException Locked="false" Priority="20" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Emphasis"/> <w:LsdException Locked="false" Priority="59" SemiHidden="false" UnhideWhenUsed="false" Name="Table Grid"/> <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Placeholder Text"/> <w:LsdException Locked="false" Priority="1" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="No Spacing"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 1"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 1"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 1"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 1"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 1"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 1"/> <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Revision"/> <w:LsdException Locked="false" Priority="34" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="List Paragraph"/> <w:LsdException Locked="false" Priority="29" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Quote"/> <w:LsdException Locked="false" Priority="30" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Quote"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 1"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 1"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 1"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 1"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 1"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 1"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 1"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 1"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 2"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 2"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 2"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 2"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 2"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 2"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 2"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 2"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 2"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 2"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 2"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 2"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 2"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 2"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 3"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 3"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 3"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 3"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 3"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 3"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 3"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 3"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 3"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 3"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 3"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 3"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 3"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 3"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 4"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 4"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 4"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 4"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 4"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 4"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 4"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 4"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 4"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 4"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 4"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 4"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 4"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 4"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 5"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 5"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 5"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 5"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 5"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 5"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 5"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 5"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 5"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 5"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 5"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 5"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 5"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 5"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 6"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 6"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 6"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 6"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 6"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 6"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 6"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 6"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 6"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 6"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 6"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 6"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 6"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 6"/> <w:LsdException Locked="false" Priority="19" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtle Emphasis"/> <w:LsdException Locked="false" Priority="21" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Emphasis"/> <w:LsdException Locked="false" Priority="31" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtle Reference"/> <w:LsdException Locked="false" Priority="32" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Reference"/> <w:LsdException Locked="false" Priority="33" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Book Title"/> <w:LsdException Locked="false" Priority="37" Name="Bibliography"/> <w:LsdException Locked="false" Priority="39" QFormat="true" Name="TOC Heading"/> </w:LatentStyles></xml><![endif]--><!--[if gte mso 10]><style> /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-priority:99; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin-top:0cm; mso-para-margin-right:0cm; mso-para-margin-bottom:10.0pt; mso-para-margin-left:0cm; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-fareast-language:EN-US;} </style><![endif]--><b><span style="line-height: 115%;">Jerry Ward </span></b><span style="line-height: 115%;">co-founder @Viscosity North America</span>&nbsp;</span></span></span></span></li><li><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><b><span style="line-height: 115%;">Lino Schildenfeld</span></b><span style="line-height: 115%;">Oracle ACE Associate @APEX R&amp;D, Australia</span></span></span></li></ul><span style="font-size: large;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><b>Register now</b></span></span><br /><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">You can register directly using links <span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">below</span> or through <a href="http://www.ausoug.org.au/pages/calendar" target="_blank">AUSOUG </a>website.</span></span></span></span></span></span></span></span></span></span></span><br /><br /><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">Scheduled sessions<span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">:</span></span></span><!--[if gte mso 9]><xml> <o:OfficeDocumentSettings> <o:AllowPNG/> </o:OfficeDocumentSettings></xml><![endif]--> <br /><table border="0" cellpadding="0" cellspacing="0" class="MsoNormalTable" style="margin-left: 42.55pt; mso-cellspacing: 0cm; mso-padding-alt: 0cm 0cm 0cm 0cm; mso-yfti-tbllook: 1184; width: 576px;"> <tbody><tr style="height: 34.1pt; mso-yfti-firstrow: yes; mso-yfti-irow: 0;"> <td style="height: 34.1pt; padding: 0cm;"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">July 10, 2018 06:00pm AEST</span></span></div></td> <td style="height: 34.1pt; padding: 0cm; width: 222.6pt;" width="297"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><a href="http://www.ausoug.org.au/cms/rest/event/2352"><span style="color: blue;">On Oracle APEX 18.1</span></a></span></span></div></td> </tr><tr style="height: 34.1pt;"> <td style="height: 34.1pt; padding: 0cm;"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">July 17, 2018 08:00pm AEST</span></span></div></td> <td style="height: 34.1pt; padding: 0cm; width: 222.6pt;" width="297"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><a href="http://www.ausoug.org.au/cms/rest/event/2353"><span style="color: blue;">Dive into Dynamic Actions</span></a></span></span></div></td> </tr><tr style="height: 34.1pt;"> <td style="height: 34.1pt; padding: 0cm;"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">July 24, 2018 09:00pm AEST</span></span></div></td> <td style="height: 34.1pt; padding: 0cm; width: 222.6pt;" width="297"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><a href="http://www.ausoug.org.au/cms/rest/event/2354"><span style="color: blue;">Building Big Things for Small Screens</span></a></span></span></div></td> </tr><tr style="height: 34.1pt;"> <td style="height: 34.1pt; padding: 0cm;"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">July 31, 2018 09:00pm AEST</span></span></div></td> <td style="height: 34.1pt; padding: 0cm; width: 222.6pt;" width="297"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><a href="http://www.ausoug.org.au/cms/rest/event/2355"><span style="color: blue;">Universa<span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">l theme<span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">:</span> </span></span>Understanding Core Technology and Lesser-Known Features</span></a></span></span></div></td> </tr><tr style="height: 34.1pt;"> <td style="height: 34.1pt; padding: 0cm;"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">August 09, 2018 06:00pm AEST</span></span></div></td> <td style="height: 34.1pt; padding: 0cm; width: 222.6pt;" width="297"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><a href="http://www.ausoug.org.au/cms/rest/event/2356"><span style="color: blue;">APEX 18.1 and Beyond</span></a></span></span></div></td> </tr><tr style="height: 34.1pt;"> <td style="height: 34.1pt; padding: 0cm;"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">August 14, 2018 09:00pm AEST</span></span></div></td> <td style="height: 34.1pt; padding: 0cm; width: 222.6pt;" width="297"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><a href="http://www.ausoug.org.au/cms/rest/event/2357"><span style="color: blue;">Why Your DBA Hates You (Basic Tips for Tuning Your SQL)</span></a></span></span></div></td> </tr><tr style="height: 34.1pt;"> <td style="height: 34.1pt; padding: 0cm;"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">August 21, 2018 06:00pm AEST</span></span></div></td> <td style="height: 34.1pt; padding: 0cm; width: 222.6pt;" width="297"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><a href="http://www.ausoug.org.au/cms/rest/event/2369"><span style="color: blue;">Customizing the Interactive Grid with Plugins</span></a></span></span></div></td> </tr><tr style="height: 34.1pt; mso-yfti-irow: 6; mso-yfti-lastrow: yes;"> <td style="height: 34.1pt; padding: 0cm;"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">August 28, 2018 06:00pm AEST</span></span></div></td> <td style="height: 34.1pt; padding: 0cm; width: 222.6pt;" width="297"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><a href="http://www.ausoug.org.au/cms/rest/event/2365"><span style="color: blue;">Automated Browser Tests with APEX</span></a></span></span></div></td> </tr><tr style="height: 34.1pt; mso-yfti-irow: 6; mso-yfti-lastrow: yes;"> <td style="height: 34.1pt; padding: 0cm;"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">September 06, 2018 09:00pm AEST</span></span></div></td> <td style="height: 34.1pt; padding: 0cm; width: 222.6pt;" width="297"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><a href="http://www.ausoug.org.au/cms/rest/event/2360"><span style="color: blue;">Advanced CSS Techniques to Make Your Application Look Even Better</span></a></span></span></div></td> </tr><tr style="height: 34.1pt; mso-yfti-irow: 6; mso-yfti-lastrow: yes;"> <td style="height: 34.1pt; padding: 0cm;"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">September 10, 2018 06:00pm AEST</span></span></div></td> <td style="height: 34.1pt; padding: 0cm; width: 222.6pt;" width="297"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><a href="http://www.ausoug.org.au/cms/rest/event/2358"><span style="color: blue;">Bringing Virtual Reality (VR) and Augmented Reality (AR) to APEX</span></a></span></span></div></td> </tr><tr style="height: 34.1pt; mso-yfti-irow: 6; mso-yfti-lastrow: yes;"> <td style="height: 34.1pt; padding: 0cm;"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">September 18, 2018 06:00pm AEST</span></span></div></td> <td style="height: 34.1pt; padding: 0cm; width: 222.6pt;" width="297"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><a href="http://www.ausoug.org.au/cms/rest/event/2363"><span style="color: blue;">APEX Internal Workspace</span></a></span></span></div></td> </tr><tr style="height: 34.1pt; mso-yfti-irow: 6; mso-yfti-lastrow: yes;"> <td style="height: 34.1pt; padding: 0cm;"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">September 25, 2018 06:00pm AEST</span></span></div></td> <td style="height: 34.1pt; padding: 0cm; width: 222.6pt;" width="297"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><a href="http://www.ausoug.org.au/cms/rest/event/2376"><span style="color: blue;">PL/SQL tuning</span></a></span></span></div></td> </tr><tr style="height: 34.1pt; mso-yfti-irow: 6; mso-yfti-lastrow: yes;"> <td style="height: 34.1pt; padding: 0cm;"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">October 02, 2018 09:00pm AEST</span></span></div></td> <td style="height: 34.1pt; padding: 0cm; width: 222.6pt;" width="297"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><a href="http://www.ausoug.org.au/cms/rest/event/2361"><span style="color: blue;">Hacking Oracle APEX</span></a></span></span></div></td> </tr><tr style="height: 34.1pt; mso-yfti-irow: 6; mso-yfti-lastrow: yes;"> <td style="height: 34.1pt; padding: 0cm;"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">October 09, 2018 09:00pm AEST</span></span></div></td> <td style="height: 34.1pt; padding: 0cm; width: 222.6pt;" width="297"><div class="MsoNormal" style="line-height: normal;"><span style="font-size: small;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><a href="http://www.ausoug.org.au/cms/rest/event/2362"><span style="color: blue;">Timecards and Timekeeping in Five Acts: Microapps in APEX for Web, Desktop, Slack, SMS, and Voice</span></a></span></span></div></td> </tr></tbody></table><div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/-JQzC68fzGEU/WzHTJ6qOngI/AAAAAAAAMHY/9Rn8snWbMAku3sy3ysw2oRZ-rnbll696ACK4BGAYYCw/s1600/AUSOUG.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://1.bp.blogspot.com/-JQzC68fzGEU/WzHTJ6qOngI/AAAAAAAAMHY/9Rn8snWbMAku3sy3ysw2oRZ-rnbll696ACK4BGAYYCw/s400/AUSOUG.jpg" /></a></div><br /><div style="text-align: justify;"></div><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">*A<span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">s additional sess<span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">ions are <span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">scheduled</span> this blog will be upd<span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">a<span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">ted.</span></span></span></span></span></span></span><br /><br /><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">Happy APEXing,</span></span><br /><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;"><span style="font-family: &quot;arial&quot; , &quot;helvetica&quot; , sans-serif;">Lino </span></span></div> SLino tag:blogger.com,1999:blog-8185384792158425670.post-5527779240429968755 Tue Jun 26 2018 02:35:00 GMT-0400 (EDT) APEX_ITEM Parte 1 Guardando Check Boxes con APEX_APPLICATION.G_F01 en reportes + Oracle Apex https://aflorestorres.blogspot.com/2018/06/apexitem-parte-1-guardando-check-boxes.html En este tutorial vamos a trabajar con los apex_item, en el caso particular de los checkbox dentro de reportes.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-7IhgrnlPHKM/Wy2zfoSuv2I/AAAAAAAAMa4/JNhaZ9UtvwEK15CKdJqpBGl3cWLs4dB3ACLcBGAs/s1600/Capture.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="415" data-original-width="813" height="163" src="https://3.bp.blogspot.com/-7IhgrnlPHKM/Wy2zfoSuv2I/AAAAAAAAMa4/JNhaZ9UtvwEK15CKdJqpBGl3cWLs4dB3ACLcBGAs/s320/Capture.PNG" width="320" /></a></div><br /><br />Lo primero a tener en cuenta es que usaremos APEX_ITEM ,aqui les lejo el <a href="https://docs.oracle.com/cd/E71588_01/AEAPI/APEX_ITEM.htm#AEAPI192" target="_blank">link de la documentacion oficial</a>, con apex_item podemos crear diferentes controles, como texto, listas de seleccion, etc.<br /><br />El metodo nativo para guardar la informacion de esto es usar&nbsp;APEX_APPLICATION.G_F01 donde el 01, nos referenciara al identificador del apex_item.<br /><br />Quiero aclarar que APEX_APPLICATION.G_F01 solo tendra valores cuando hagamos submit a la pagina, es decir que si los queremos usar con acciones dinamicas no podras obtener el valor. Para esto voy a crear otros post adicionales, para mostrarles como podriamos guardar esta informacion sin hacer submit.<br /><br /><span style="font-size: x-small;"><i>proximamente mantener el valor de check box en paginacion</i></span><br /><span style="font-size: x-small;"><i>proximamente guardado automatico de apex_items</i></span><br /><br /><a href="https://apex.oracle.com/pls/apex/f?p=32431:20:112687540016083:::::" target="_blank">Link demo</a><br />user: demo&nbsp; /pass:&nbsp; demo<br /><br /><a href="https://youtu.be/kbKGQSHSy50" target="_blank">Link video tutorial</a><br /><br /><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/kbKGQSHSy50/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/kbKGQSHSy50?feature=player_embedded" width="320"></iframe></div><br /><br />Entonces, primero definimos una estructura basica del query agregando el apex_item.checkbox2<br /><br /><!-- HTML generated using hilite.me --><br /><div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">select</span> empno<br /> , apex_item.hidden(p_idx <span style="color: #333333;">=&gt;</span> <span style="color: #0000dd; font-weight: bold;">1</span> <br /> , p_value <span style="color: #333333;">=&gt;</span> empno) <span style="color: #333333;">||</span><br /> apex_item.checkbox2(p_idx <span style="color: #333333;">=&gt;</span> <span style="color: #0000dd; font-weight: bold;">2</span><br /> , p_value <span style="color: #333333;">=&gt;</span> empno) CheckBox<br /> , ename<br /> , deptno<br /> , sal<br /> , comm<br /> , job<br /> <span style="color: #008800; font-weight: bold;">from</span> emp<br /><span style="color: #008800; font-weight: bold;">where</span> deptno <span style="color: #333333;">&lt;&gt;</span> :P18_DEPARTAMENTOS<br /></pre></div><br />*Notamos que usamos un apex_item.hidden que se usara como indice principal.<br />* La clausula where es para no mostrar los registros que ya se hayan seleccionado para ese departamento.<br /><br />Creamos un proceso que hara lo siguiente:<br /><br /><!-- HTML generated using hilite.me --><br /><div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">for</span> i <span style="color: #008800; font-weight: bold;">in</span> <span style="color: #0000dd; font-weight: bold;">1</span>..apex_application.g_f01.<span style="color: #008800; font-weight: bold;">count</span> loop<br /> <span style="color: #008800; font-weight: bold;">for</span> j <span style="color: #008800; font-weight: bold;">in</span> <span style="color: #0000dd; font-weight: bold;">1</span>..apex_application.g_f02.<span style="color: #008800; font-weight: bold;">count</span> loop<br /> if apex_application.g_f01(i) <span style="color: #333333;">=</span> apex_application.g_f02(j) <span style="color: #008800; font-weight: bold;">then</span><br /> <span style="color: #888888;">-- esta seleccionado</span><br /> <span style="color: #008800; font-weight: bold;">update</span> emp <br /> <span style="color: #008800; font-weight: bold;">set</span> deptno <span style="color: #333333;">=</span> :P18_DEPARTAMENTO<br /> <span style="color: #008800; font-weight: bold;">where</span> empno <span style="color: #333333;">=</span> apex_application.g_f02(i);<br /> <span style="color: #008800; font-weight: bold;">end</span> if;<br /> <span style="color: #008800; font-weight: bold;">end</span> loop; <br /><span style="color: #008800; font-weight: bold;">end</span> loop;<br /></pre></div><br />*Dos loops, uno para tomar todos los indices, y el otro para tomar solo los seleccionados, luego se hace el update.<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /> Angel O. Flores Torres tag:blogger.com,1999:blog-2893325831811936253.post-2787445329523787998 Mon Jun 25 2018 09:47:00 GMT-0400 (EDT) Have I been Pwned? http://gasparyyc.strikingly.com/blog/have-i-been-pwned <h3><p>What is pwned? - Lets set it straight..</p></h3><p>In jargon, pwn means to <u>compromise or control</u>, <u>specifically another computer (server or PC), website, gateway device, or application</u></p><h3><p>So? What’s the issue here?</p></h3><p>Multiple security breaches have made millions of passwords known to cybercriminals</p><p>Yes, possibly one of YOUR password is already known to cyber-criminals.</p><p> </p><p>Add paragraph text here.</p><p>Not just passwords, recent breaches have confirmed emails, passwords, names, IP address and physical addresses have been stolen, also</p><ul><li>Usernames</li><li>Dates of birth</li><li>Genders</li><li>Phone numbers</li></ul><p>Just what cyber-criminals want for identify theft!</p><h3><p>Really, how bad is it??</p></h3><p>Look at numbers!!</p><p>Passwords:</p><ul><li>By March 2018, <strong>501 million </strong>searchable passwords are available for download!</li></ul><h3><p>What can I do??</p></h3><p>Add par</p><ol><li>Get a password manager and learn how to use it:  1password.com, keepass.org, etc..</li><li>Change your passwords across the board…</li><li>Use this information to your advantage and:</li></ol><ul><li>Show the users you’re ahead of the game</li><li>Show the users you know what to do</li><li>Lead the change, be the expert at work</li><li>Don’t forget Home & Family.. They need professional advise too…</li></ul><h3><p>But how is this related to APEX?</p></h3><p>Follow this blog to show you how to download the password files and using APEX you can check if your passwords have been known to cyber-criminals..</p><p>Also with a little bit of creativity we can allow our users to check if their password has been compromised already so they can change it..</p><p>Or you could enforce a check that if its compromised then that password can’t be used in your application(s).</p><h3><p>So, how to do it from APEX?</p></h3><p>There are a few steps and you’ll decide what works best in your case.</p><p>–These are steps...<a href=http://gasparyyc.strikingly.com/blog/have-i-been-pwned>Read More</a> http://gasparyyc.strikingly.com/blog/have-i-been-pwned Sat Jun 23 2018 20:26:03 GMT-0400 (EDT) Kscope Highlights – Ideas, Friends, Fun https://insum.ca/kscope-highlights-ideas-friends-fun/ <div tabindex="0" aria-label="Message Contents"> <div class="_rp_m5" tabindex="-1" aria-label="Expanded Message Contents"> <div class="_rp_Y4 ms-border-color-neutralLight ShowReferenceAttachmentsLinks ShowConsesusSchedulingLink" tabindex="-1"> <div class="_rp_b5 _rp_a5"> <div role="document"> <div id="Item.MessagePartBody" class="_rp_05"> <div id="Item.MessageUniqueBody" class="_rp_15 ms-font-weight-regular ms-font-color-neutralDark rpHighlightAllClass rpHighlightBodyClass"> <div dir="ltr"> <div id="divtagdefaultwrapper"> <div> <p><em>Kscope 2018 was held in Orlando, Fl. from June 10 to June 14 </em></p> <p>Seeing as only a fraction of the total APEX community can actually attend in person, it becomes necessary to report back and to provide our take, our opinions of the week that was KScope. This is also good information for those actually in attendance because with so much content being delivered concurrently, there&#8217;s just no way to catch it all.</p> <h2>Monty Latiolais</h2> <p>Hard to believe, but true. This was my first time in Orlando. Back in the 80&#8217;s I did get a chance to go to Disneyland (Anaheim, CA) but never Disneyworld in Orlando. Wasn&#8217;t able to see any of the parks or anything, so a return trip is necessary. I&#8217;m thinking the <a href="https://www.heug.org/p/bl/et/blogid=2531">HEUG Alliance Conference</a> in March may be a good time to finally strap on the mouse ears.</p> <p>On to the conference&#8230;</p> <p>One highlight for me was the Insum Vendor Presentation. This year we took a different approach. We decided to effectively &#8220;yield the balance of our time.&#8221;</p> <p><img class="size-medium wp-image-11873 alignleft" src="https://insum.ca/wp-content/uploads/2018/06/kscope-APEX-vendor-session-300x225.jpg" alt="Kscope Insum Vendor Session" width="300" height="225" srcset="https://insum.ca/wp-content/uploads/2018/06/kscope-APEX-vendor-session-300x225.jpg 300w, https://insum.ca/wp-content/uploads/2018/06/kscope-APEX-vendor-session-600x450.jpg 600w, https://insum.ca/wp-content/uploads/2018/06/kscope-APEX-vendor-session-450x338.jpg 450w, https://insum.ca/wp-content/uploads/2018/06/kscope-APEX-vendor-session.jpg 700w" sizes="(max-width: 300px) 100vw, 300px" />-We took the hour and handed it right back to the APEX Community in hosting <a href="https://twitter.com/mikehichwa1">Mike Hichwa</a>, <a href="https://twitter.com/joelkallman">Joel Kallman</a>, and the entire APEX Dev Team. The interview format seemed most appropriate. Great crowd&#8230;great questions&#8230;even better answers.  Did you know the first APEX external customer was the Chicago Police Department? Several longtime APEX Community members told me afterward they learned a thing or two about the origins of our favorite RAD tool. It was a good feeling providing visibility to those so responsible for the success we now enjoy.</p> <p>-My other highlight occurred Wednesday morning. Bright and early, Insum&#8217;s own Jackie McIlroy and I brought to the stage &#8216;Low Cost, Low Code BI with APEX and Analytic Views&#8217;. I must say I was nervous, no, make that excited, because we both stepped out of our comfort zone. We weren&#8217;t talking to an APEX audience in the APEX track. No, we were speaking in the EPM Reporting, BI Analytics, and Visualizations Track. However, based on the audience response (and session evals) it was a rousing success. It seems people are interested in inexpensive, simple solutions to their problems. Who&#8217;d a thunk it?</p> <p>The week went by quickly, as is the norm, but this week there was a different vibe in the Insum booth. There&#8217;s a quiet confidence that comes with years of experience. Customers (and future customers) time and again came to the booth thanking us for the tweets, blogs, webinars and personal appearances throughout the year. Feedback like that only makes us want to do more. In fact, I tweeted this out&#8230;.</p> </div> <div><img id="img910277" class="aligncenter" src="data:image/png;base64,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" width="455" height="178" crossorigin="use-credentials" data-imagetype="AttachmentByCid" data-custom="AAMkADZkMDM2ZDAzLTVhNDItNDdlNS05NjVkLWEwZTNiNDM3N2Y4YgBGAAAAAABSmbNgbSVgToM1tINXZQkhBwArObMufL3cQoQDu%2BkkvepWAAAAAAEMAAArObMufL3cQoQDu%2BkkvepWAABuZ%2BgKAAABEgAQAI5C2pssIFJHlpfobFd18rk%3D" data-outlook-trace="F:1|T:1" data-downloadimage="service.svc/s/GetFileAttachment?id=AAMkADZkMDM2ZDAzLTVhNDItNDdlNS05NjVkLWEwZTNiNDM3N2Y4YgBGAAAAAABSmbNgbSVgToM1tINXZQkhBwArObMufL3cQoQDu%2BkkvepWAAAAAAEMAAArObMufL3cQoQDu%2BkkvepWAABuZ%2BgKAAABEgAQAI5C2pssIFJHlpfobFd18rk%3D&amp;X-OWA-CANARY=qu75Z7ibqEqsn889J_QKV9Dx4Ad019UYRlwVA9x8dmc3obPJIGNUS-Pt1M-kWQGbrv4FZWss4fs." data-thumbnailimage="https://attachment.outlook.office.net/owa/mruel@insum.ca/service.svc/s/GetFileAttachment?id=AAMkADZkMDM2ZDAzLTVhNDItNDdlNS05NjVkLWEwZTNiNDM3N2Y4YgBGAAAAAABSmbNgbSVgToM1tINXZQkhBwArObMufL3cQoQDu%2BkkvepWAAAAAAEMAAArObMufL3cQoQDu%2BkkvepWAABuZ%2BgKAAABEgAQAI5C2pssIFJHlpfobFd18rk%3D&amp;X-OWA-CANARY=qu75Z7ibqEqsn889J_QKV9Dx4Ad019UYRlwVA9x8dmc3obPJIGNUS-Pt1M-kWQGbrv4FZWss4fs.&amp;token=eyJhbGciOiJSUzI1NiIsImtpZCI6IjA2MDBGOUY2NzQ2MjA3MzdFNzM0MDRFMjg3QzQ1QTgxOENCN0NFQjgiLCJ4NXQiOiJCZ0Q1OW5SaUJ6Zm5OQVRpaDhSYWdZeTN6cmciLCJ0eXAiOiJKV1QifQ.eyJ2ZXIiOiJFeGNoYW5nZS5DYWxsYmFjay5WMSIsImFwcGN0eHNlbmRlciI6Ik93YURvd25sb2FkQDA1OWUyOTI1LTQ4MmMtNDAzMi1iNDk1LTZhYzc4NjFkZWU5MyIsImFwcGN0eCI6IntcIm1zZXhjaHByb3RcIjpcIm93YVwiLFwicHJpbWFyeXNpZFwiOlwiUy0xLTUtMjEtNDA5MDI4NTMzNy0zMDY3OTAxMTgyLTM4ODAxNzkwODQtMTQ2NDE4MjJcIixcInB1aWRcIjpcIjExNTM4MzYyOTY3OTUxOTY5NTFcIixcIm9pZFwiOlwiNTg3ZjZhNGQtNDk0Mi00YThlLWE5MzYtZWNlY2FhYzQ5YjQxXCIsXCJzY29wZVwiOlwiT3dhRG93bmxvYWRcIn0iLCJuYmYiOjE1Mjk1ODQ2NTgsImV4cCI6MTUyOTU4NTI1OCwiaXNzIjoiMDAwMDAwMDItMDAwMC0wZmYxLWNlMDAtMDAwMDAwMDAwMDAwQDA1OWUyOTI1LTQ4MmMtNDAzMi1iNDk1LTZhYzc4NjFkZWU5MyIsImF1ZCI6IjAwMDAwMDAyLTAwMDAtMGZmMS1jZTAwLTAwMDAwMDAwMDAwMC9hdHRhY2htZW50Lm91dGxvb2sub2ZmaWNlLm5ldEAwNTllMjkyNS00ODJjLTQwMzItYjQ5NS02YWM3ODYxZGVlOTMifQ.DAhHYqPavhWrI4mYKxO0-4JQiJrgTNGmsNaWAOMQMtGwgsVymsSvPEshlpY23dYJ6P8YY0-6Z7UzoNku-n9Zz75rjixiBcv8OgaKULbY5ji76xWo6PE4h1xuq4iXCnCB6qHWYLK-3l5N9xC98Lp9PIv905AiCQvblbwfalivcGProhPjnny_mnPKhiBnlkPzr4FrFmizqG5fU3qaPuWADppvEC_q3xTtsLhYTNUYJi1sdJAYxi5XtCb5NMnX5kEz2pVBI4P4VmfpKv7F-MKe-fV43Lg8SD4KtN6INiZwplHTd41agx7dBAEBq3Lr7nhaJzqHfaWvbGHK6P4Pq_85SQ&amp;owa=outlook.office.com&amp;isImagePreview=True" /></div> <p>&nbsp;</p> <div>Finally, if you&#8217;re reading this post, you&#8217;re aware we&#8217;ve rolled out a new website. I like it. It&#8217;s clean, professional and by my eyeballs&#8230;fast. But,  it&#8217;s more important to know what you think. Drop us your feedback below!</div> </div> </div> </div> </div> <h2 tabindex="-1" aria-expanded="false" aria-haspopup="false">Hayden Hudson</h2> <p><img class=" wp-image-11882 alignright" src="https://insum.ca/wp-content/uploads/2018/06/Hayden-Hudson.jpg" alt="kscope Hayden Martin David" width="142" height="188" /></p> <div class="_pe_d _pe_92" tabindex="-1" aria-expanded="false" aria-haspopup="false">Not sure why I bothered to bring pleasure-reading and gym clothes to Kscope &#8230; I should have remembered from last year that Kscope is packed to the gills with so many learning and networking opportunities that you barely have time to catch your breath. At every moment of every day, there are always several events you are missing. I had the privilege this year to present 2 sessions, an experience that helped me really feel like I was part of the broader APEX network. I came back from the trip more motivated than ever to further my learning and up my contributions to the APEX community.</div> <p>&nbsp;</p> </div> </div> </div> </div> </div> <h2 tabindex="-1" aria-expanded="false" aria-haspopup="false"></h2> <h2 tabindex="-1" aria-expanded="false" aria-haspopup="false">Martin D&#8217;Souza</h2> <div tabindex="0" aria-label="Message Contents"> <div class="_rp_m5" tabindex="-1" aria-label="Expanded Message Contents"> <div tabindex="-1" aria-expanded="false" aria-haspopup="false"> <div class="">Kscope 18 was a great time as always.  I wasn’t able to see all the presentations I was hoping to but thankfully some of them were recorded and I look forward to seeing them soon. I have four highlights from the conference:</div> <div class=""> <div id="attachment_11861" style="width: 142px" class="wp-caption alignleft"><img class="wp-image-11861 " src="https://insum.ca/wp-content/uploads/2018/06/MartinDuck-kscope-169x300.jpeg" alt="Kscope VR Duck Martin" width="132" height="234" srcset="https://insum.ca/wp-content/uploads/2018/06/MartinDuck-kscope-169x300.jpeg 169w, https://insum.ca/wp-content/uploads/2018/06/MartinDuck-kscope.jpeg 180w" sizes="(max-width: 132px) 100vw, 132px" /><p class="wp-caption-text">A duck snuck into the presentation <img src="https://s.w.org/images/core/emoji/11/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p></div> </div> <div></div> <div></div> <div class="">&#8211; Dimitri Gielis (<a href="https://twitter.com/dgielis">@dgielis</a> ) talk on AR/VR in APEX. It opened my eyes of some possibilities to use in the future.</div> <div class=""></div> <div></div> <div class=""><i class=""> </i></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div class="">&#8211; Emerging Tech unconference: There was a special sub-track focused on emerging technologies. I co-moderated an unconferece session on Wednesday morning with Natalie Delmar (<a href="https://twitter.com/essbaselady?">@essbaselady</a>). We got to see some great presentations on lots of technologies including chatbots, blockchain, Alexa, and AR/VR. If this happens again next year I highly suggest attending it!</div> <div class=""></div> <div class="">&#8211; I’ve had the pleasure to know Adrian Png (<a href="https://twitter.com/fuzziebrain?">@fuzziebrain</a>) for many years. Over the years I’ve worked with him as a volunteer with ODTUG, on some open source projects, and at <a href="https://insum.ca/">Insum</a>. I was really happy to see that he became an Oracle ACE Associate!</div> <div class=""></div> <div class="">&#8211; Like all years, Kscope is a great place to meet some really smart and interesting people. Talking with everyone has given me a lot of ideas on how to improve processes and also think differently about problems.</div> <h2>David Schleis</h2> <p>This was my twentie<img class="size-medium wp-image-11877 alignleft" src="https://insum.ca/wp-content/uploads/2018/06/Kscope-David-and-Richard-300x200.jpg" alt="Kscope David Richard and Francis" width="300" height="200" srcset="https://insum.ca/wp-content/uploads/2018/06/Kscope-David-and-Richard-300x200.jpg 300w, https://insum.ca/wp-content/uploads/2018/06/Kscope-David-and-Richard-600x399.jpg 600w, https://insum.ca/wp-content/uploads/2018/06/Kscope-David-and-Richard-450x300.jpg 450w, https://insum.ca/wp-content/uploads/2018/06/Kscope-David-and-Richard.jpg 700w" sizes="(max-width: 300px) 100vw, 300px" />th consecutive ODTUG conference (<em>Editor&#8217;s Note: Wow!</em>) and my third as an employee of the best team in the APEX world. While my time at the conference was restricted this year by a coincidental extended family vacation, I did get to attend a couple of sessions, learning something new at each one. I love the invigorating feeling of discovery that this conference provides, and I can still recall that feeling from the very first time I attended. It absolutely changed my life.</p> <p>I also got to catch up with some of the many friends that I have made over the years, and one such encounter made a lasting impact. A friend told me that this would be her last Kscope because she would be retiring this year, which is good for her, but not her employer. You see, she is the APEX-person in her shop; the one who discovered the tool and made applications that they now cannot function without. She told me that she has talked with coworkers and management, trying to get them to understand that even though APEX is “easy” it’s not trivial, and the applications that she has created will need support.</p> <p>She is worried, and for good reason. But I was happy that I could tell her that Insum has an answer for her. As long as her company is aware of Insum and our ZenIT solution, she can rest assured that her applications will receive all the attention they need, so she can spend her days concentrating on more important things such as, remembering what a nap feels like…</p> <h2>Anton Nielsen</h2> <p><img class="size-medium wp-image-11866 alignright" src="https://insum.ca/wp-content/uploads/2018/06/Kscope-Anton-shocks-his-audience-289x300.jpg" alt="Kscope Anton Shocks his audence" width="289" height="300" srcset="https://insum.ca/wp-content/uploads/2018/06/Kscope-Anton-shocks-his-audience-289x300.jpg 289w, https://insum.ca/wp-content/uploads/2018/06/Kscope-Anton-shocks-his-audience.jpg 323w" sizes="(max-width: 289px) 100vw, 289px" /></p> </div> <p>I wish I had a record of the first KScope I attended. I think Rich Soule was there. We both worked at Oracle at the time, so it was at least 13 years ago, perhaps 18.</p> <p>I’ve attended most years since and it is always a highlight of my year. The conference provides me with three great ways to improve my knowledge and skills. I’ve presented every year that I’ve attended. Each presentation is a stretch of my own knowledge. Refining existing knowledge and experience into a formal presentation brings greater insight into a topic—and often highlights areas that require additional research to truly provide guidance to others. Developing a presentation is as valuable to me as attending one.</p> <p>Of course, attending presentations is the second way that KScope is valuable—and exhausting. There are always at least 2 valuable presentations in each time slot, and getting to as many as I can, plus waking up for a 5k run, makes for a long week, but all worth it!</p> <p>And finally, meeting with the luminaries available outside of the scheduled events, around a lunch table or at the “special event,” provides an incredible opportunity to gain insights into the past, present, and future of our industry. More than all of this, though, I value the friendships I have with members of the community—great people to have built a career with.</p> <h2>Jackie McIlroy</h2> <div><img class="size-medium wp-image-11867 alignleft" src="https://insum.ca/wp-content/uploads/2018/06/kscope-Jackie-Monty-265x300.jpg" alt="" width="265" height="300" srcset="https://insum.ca/wp-content/uploads/2018/06/kscope-Jackie-Monty-265x300.jpg 265w, https://insum.ca/wp-content/uploads/2018/06/kscope-Jackie-Monty.jpg 348w" sizes="(max-width: 265px) 100vw, 265px" /></div> <div>Wow, what a week!  This was my second Kscope and best yet.  My favorite part of the week has to be interacting with the APEX community.  I just love meeting new people who are interested in APEX and catching up with friends and colleagues that I rarely see in person.   This year I really enjoyed the Sunday Symposium and the chance to learn from the APEX team themselves.  I also had the privilege of being a speaker this year.  I loved the opportunity to share a little knowledge with the APEX Community, and I hope I get the chance to do so again in the future.</div> <h2></h2> <h2></h2> <h2></h2> <h2></h2> <h2>Adrian Png</h2> <p>Kscope conferences are not only full of content but also have plentiful opportunities to meet new friends, co-workers and most especially, clients! I enjoyed very much the interactions. Location-wise, Disney World was great for this year’s event, and it was pleasing to see many families coming along to enjoy the magical experience.</p> <p>For me, two themes stood out this year: Blockchains and JavaScript. As much as I wanted to, I didn’t have the opportunity to attend as many<img class="size-medium wp-image-11868 alignright" src="https://insum.ca/wp-content/uploads/2018/06/Kscope-Adrian-and-ACEs-2-1-300x200.jpg" alt="Kscope Adrian and ACEs" width="300" height="200" srcset="https://insum.ca/wp-content/uploads/2018/06/Kscope-Adrian-and-ACEs-2-1-300x200.jpg 300w, https://insum.ca/wp-content/uploads/2018/06/Kscope-Adrian-and-ACEs-2-1-600x399.jpg 600w, https://insum.ca/wp-content/uploads/2018/06/Kscope-Adrian-and-ACEs-2-1-450x300.jpg 450w, https://insum.ca/wp-content/uploads/2018/06/Kscope-Adrian-and-ACEs-2-1.jpg 700w" sizes="(max-width: 300px) 100vw, 300px" /> Blockchain-related sessions. There’s just so much knowledge out there to absorb and too little time. On JavaScript, I felt Dan McGhan’s <a href="https://twitter.com/hashtag/letswreckthistogether?">#LetsWreckThisTogether</a> presentation was very smooth and impressive. It clearly demonstrated the power of “us”, and how you could put together an excellent presentation by creating a collage of crowd-sourced ideas from the community. As Monty Latiolais aptly puts it: “The Oracle APEX community is like no other.”</p> <p>This year, of course, is an extra special year with the Oracle ACE Associate nomination. I am honored and humbled. The award is also an important moment to remember those who have contributed significantly to my career working with Oracle Application Express. The honor roll is too long to list, you know who you are. Going forward, the best way to demonstrate my appreciation is to pay it forward and help others grow and be successful.</p> <h2>Francis Mignault</h2> <p><img class="size-medium wp-image-11878 alignleft" src="https://insum.ca/wp-content/uploads/2018/06/Kscope-Francis-and-Friends-300x200.jpg" alt="Kscope Francis and friends" width="300" height="200" srcset="https://insum.ca/wp-content/uploads/2018/06/Kscope-Francis-and-Friends-300x200.jpg 300w, https://insum.ca/wp-content/uploads/2018/06/Kscope-Francis-and-Friends-600x399.jpg 600w, https://insum.ca/wp-content/uploads/2018/06/Kscope-Francis-and-Friends-450x300.jpg 450w, https://insum.ca/wp-content/uploads/2018/06/Kscope-Francis-and-Friends.jpg 700w" sizes="(max-width: 300px) 100vw, 300px" />This year, Kscope18 was, again, a super great conference. We had the chance to meet with long-time friends, make new ones and discuss with a lot of new APEX aficionados. This was my 12th Kscope and I am still impressed with everything that goes on during that week. Special events, technical sessions, hands-on labs, ACE meetings, Lunch and Learn sessions, exhibition hall, etc.</p> <p>For me, two sessions really stood out:</p> <p>-Vincent&#8217;s session on <a href="https://insum.ca/progressive-web-apps-two-worlds-colliding-everyone-benefits/">Progressive Web Apps</a> using APEX. He was able to demonstrate that you can effectively have a disconnected APEX app and get the data to sync back with the database when the network connectivity gets reactivated. This has been a request from clients for years. All of this using <a href="https://developers.google.com/web/fundamentals/codelabs/your-first-pwapp/">Google PWA techniques</a>.</p> <p>-Our vendor presentation &#8220;An Hour with Mike Hichwa and the Oracle APEX Development Team&#8221;, Hosted by Monty Latiolais. This year we decided to donate our Vendor Session to the community and we invited Mike Hichwa, VP of Software Development and the creator of APEX at Oracle and Joel Kallman Senior Director of Software Development to talk about the origins of APEX. It was a great session and we had some backstage stories about how everything came to life. A big thank you to <a href="https://twitter.com/mikehichwa1?">Mike</a> and <a href="https://twitter.com/joelkallman">Joel</a> who accepted to present and share the story of APEX with the community.</p> <p>I could go on and on about other sessions, the booth attendance and the INSUM VIP event, but as always, it has all been great.</p> <p>Oh, I have to mention that during the Special Event at the Mario Andretti&#8217;s Indoor Karting and Games, I finished 1st during my Karting race. Just saying. Well, that completed my perfect week in Orlando.</p> <p>See you all soon at other conferences or at my 13th Kscope next year <a href="https://kscope19.odtug.com/">in Seattle</a>.</p> <h2>Vincent Morneau</h2> <p><img class=" wp-image-11870 alignright" src="https://insum.ca/wp-content/uploads/2018/06/kscope-vincent-before-Nitro-preso-300x200.jpg" alt="" width="203" height="135" srcset="https://insum.ca/wp-content/uploads/2018/06/kscope-vincent-before-Nitro-preso-300x200.jpg 300w, https://insum.ca/wp-content/uploads/2018/06/kscope-vincent-before-Nitro-preso-600x399.jpg 600w, https://insum.ca/wp-content/uploads/2018/06/kscope-vincent-before-Nitro-preso-450x300.jpg 450w, https://insum.ca/wp-content/uploads/2018/06/kscope-vincent-before-Nitro-preso.jpg 700w" sizes="(max-width: 203px) 100vw, 203px" /></p> <div>Kscope18 was busier than ever for me and it was my favorite year so far. As always, the content is top-notch, but what I enjoyed most was the ability to meet people face to face. There is so much I learned that needs to be incorporated into my daily workflow!</div> <div></div&ggt; <div><img class=" wp-image-11880 alignleft" src="https://insum.ca/wp-content/uploads/2018/06/kscope-how-to-avoid-the-JavaScript-mess-vincent-morneau-300x176.jpg" alt="kscope how to avoid the JavaScript mess vincent morneau joel kallman photo" width="262" height="153" srcset="https://insum.ca/wp-content/uploads/2018/06/kscope-how-to-avoid-the-JavaScript-mess-vincent-morneau-300x176.jpg 300w, https://insum.ca/wp-content/uploads/2018/06/kscope-how-to-avoid-the-JavaScript-mess-vincent-morneau-768x451.jpg 768w, https://insum.ca/wp-content/uploads/2018/06/kscope-how-to-avoid-the-JavaScript-mess-vincent-morneau-600x353.jpg 600w, https://insum.ca/wp-content/uploads/2018/06/kscope-how-to-avoid-the-JavaScript-mess-vincent-morneau-880x517.jpg 880w, https://insum.ca/wp-content/uploads/2018/06/kscope-how-to-avoid-the-JavaScript-mess-vincent-morneau-450x265.jpg 450w, https://insum.ca/wp-content/uploads/2018/06/kscope-how-to-avoid-the-JavaScript-mess-vincent-morneau.jpg 1048w" sizes="(max-width: 262px) 100vw, 262px" />My highlight of the conference was definitely the <a href="https://twitter.com/hashtag/letswreckthistogether?">#LetsWreckThisTogether</a> talks on Thursday morning, where I got to present JavaScript tips alongside five APEX experts, and it felt really good to be part of the community. Looking forward to seeing all my friends at Kscope19 again next year.</div> <h2></h2> <h2></h2> <h2>Jorge Rimblas</h2> <p>ODTUG Kscope18 was my 7th Kscope, and yet there were a couple of notable firsts:</p> <p><img class="size-medium wp-image-11869 alignleft" src="https://insum.ca/wp-content/uploads/2018/06/kscope-Jorge-and-Neviana-photographers-280x300.jpg" alt="" width="280" height="300" srcset="https://insum.ca/wp-content/uploads/2018/06/kscope-Jorge-and-Neviana-photographers-280x300.jpg 280w, https://insum.ca/wp-content/uploads/2018/06/kscope-Jorge-and-Neviana-photographers.jpg 325w" sizes="(max-width: 280px) 100vw, 280px" />-For one reason or another, I had never attended the Community Service Day. This was my first time participating on the, newly renamed, Kathleen McCasland Community Service Day. This year we had a rewarding experience donating a few hours of our time to UP Orlando. UP Orlando provides crisis care, case management, transformative education, food and household subsidy, employment training and placement, personal empowerment training and active referrals to other collaborative social service providers to all people living in poverty and seeking to improve their situation. UP Orlando uses all these tools to provide a hand UP to the <a href="https://kscope18.odtug.com/page/community-service-day">180,000 people dealing with hunger</a> in Orange County, Florida.</p> <p>&#8211; First Kscope functioning as Content Chair. This year I had the honor of serving as the Content Chair for the Traditional Content which covers the APEX and Database tracks. The role involves many aspects, chief among, is supervision of the content selection committees and ensuring we have the best possible content. There are many behind the scenes duties and activities, but I won’t bore you with the details, because when it all works, the result is a memorable and enjoyable Kscope for all. This year we received over 1000 submissions, and more than 350 of those were for the Database and APEX tracks. The topics covered from the basics to the advanced and from the core database to front-end browser magic.</p> <p>Kscope19 will be in Seattle, Washington. Although it’s a year away, preparations are already underway to prepare the best conference yet.  Hope to make new friends and see old one there.</p> <p>&nbsp;</p> <p><img class="size-medium wp-image-11899 aligncenter" src="https://insum.ca/wp-content/uploads/2018/06/kscope-team-departure-lunch-225x300.jpg" alt="" width="225" height="300" srcset="https://insum.ca/wp-content/uploads/2018/06/kscope-team-departure-lunch-225x300.jpg 225w, https://insum.ca/wp-content/uploads/2018/06/kscope-team-departure-lunch-450x600.jpg 450w, https://insum.ca/wp-content/uploads/2018/06/kscope-team-departure-lunch.jpg 480w" sizes="(max-width: 225px) 100vw, 225px" /></p> </div> </div> <div></div> <p>The post <a rel="nofollow" href="https://insum.ca/kscope-highlights-ideas-friends-fun/">Kscope Highlights &#8211; Ideas, Friends, Fun</a> appeared first on <a rel="nofollow" href="https://insum.ca">Insum</a>.</p> Monty Latiolais https://insum.ca/?p=11852 Fri Jun 22 2018 11:28:51 GMT-0400 (EDT) O que é essa tabela HTMLDB_PLAN_TABLE? Posso apagar? http://desenvolvedorapex.blogspot.com/2018/06/o-que-e-essa-tabela-htmldbplantable.html Olá pessoal,<br /><br />hoje vamos falar sobre a tabela HTMLDB_PLAN_TABLE que aparecem em esquemas Oracle associados a algum workspace do Apex.<br /><br />Afinal, para que serve esta tabela? Posso apagá-la?<br /><br />Ao realizar uma busca por HTMLDB_PLAN_TABLE na documentação da Oracle e do Apex: <span style="color: red;"><b>No results found</b></span>.<br /><br />Caso a tabela HTMLDB_PLAN_TABLE já exista, execute o comando de dropar e após isso faça uma consulta para confirmar a não existência.<br /><span style="color: red;"><b>Observe que o Comandos SQL informa que "a tabela ou view não existe", quando um comando de SELECT é executado.</b></span><br /><br />Seguem os comandos executados:<br /><i>DROP TABLE htmldb_plan_table;</i><br /><i>SELECT * FROM htmldb_plan_table;</i><br /><br />Após isso, digite um comando de SELECT qualquer. Utilizei o comando abaixo:<br /><br /><i>SELECT *&nbsp;</i><br /><i>FROM emp e</i><br /><i>JOIN dept d ON e.deptno = d.deptno</i><br /><br />Clique em "Explicação" e verifique que o Comandos SQL apresenta o resultado equivalente ao Explain Plan da Oracle.<br />Veja referência para o Explain Plan na documentação da Oracle: <a href="https://docs.oracle.com/database/121/SQLRF/statements_9010.htm#SQLRF01601">https://docs.oracle.com/database/121/SQLRF/statements_9010.htm#SQLRF01601</a><br />Caso prefira um artigo em português, segue o do colega Tércio Costa (Oracle ACE Associate):&nbsp;&nbsp;<a href="https://oraclepress.wordpress.com/2017/01/16/explain-plan/">https://oraclepress.wordpress.com/2017/01/16/explain-plan/</a><br /><br /><br />Após isso, veja que o Apex criou a tabela htmldb_plan_table com o resultado do explain plan.<br /><br /><b><u>Conclusão</u></b><br /><br />A tabela HTMLDB_PLAN_TABLE é utilizada pelo Apex para armazenar os resultados da "Explicação" (Explain plan) de consultas e <b><u>pode ser apagado</u></b> sem medo.<br /><br /> Anderson Ferreira tag:blogger.com,1999:blog-5150514048465222719.post-8435147053015987426 Thu Jun 21 2018 16:52:00 GMT-0400 (EDT) Using NAT Gateways in Amazon AWS http://feedproxy.google.com/~r/BaigsTechnologyBlogWorld/~3/YW5Gn_F9WIU/using-nat-gateways-in-amazon-aws.html <div dir="ltr" style="text-align: left;" trbidi="on"><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://datanextsolutions.com/blog/using-nat-gateways-in-aws/" target="_blank"><img border="0" data-original-height="612" data-original-width="1600" height="243" src="https://3.bp.blogspot.com/-U205qf8LUqg/Wyu8zjcSErI/AAAAAAAADLE/uRTxMsvRiYQhrgC2DtUJlW927ZU5uyXNgCEwYBhgL/s640/nat-gateway.jpg" width="640" /></a></div><h3 style="text-align: left;"><br /></h3><h3 style="text-align: left;">Overview</h3><br />In AWS you can design your own network using VPC (Virtual Private Cloud). You can assign your own IP address ranges and split your network into Public and Private Subnets. In simple words, Public Subnet is like Green Zone where traffic from the internet is allowed while Private Subnet is DMZ where no direct internet access is allowed.<br /><br /><div><h3 style="text-align: left;">Problem</h3><br />So what if we need to install/update/upgrade software, utilities or OS on EC2 Instances running in a private subnet? one option is to manually FTP to the box and install it but sometimes is not feasible.<br /><br />For scenarios like these AWS provides us NAT Gateways (previously NAT Instances which are going to obsolete soon).<br /><br />Let’s see how to setup NAT Gateways in your VPC<br /><h3 style="text-align: left;"><br /></h3><h3 style="text-align: left;">Solution</h3><br />To configure NAT gateway follow these steps<br /><ol style="text-align: left;"><li>Make sure you have Internet Gateway route defined in Routing Table</li><li>Get the Public Subnet ID where your NAT gateway would be deployed</li><li>Create NAT Gateway</li><li>Test the Internet connectivity</li></ol></div><div><b>For detail solution with screenshots check my posts on <a href="https://datanextsolutions.com/blog/using-nat-gateways-in-aws/" target="_blank">DataNext Blog</a> and <a href="https://medium.com/@zeebaig/using-nat-gateways-in-aws-455f88887143" target="_blank">Medium.com</a>&nbsp;</b></div><div><br /></div><div><h4 style="text-align: left;"><a href="https://datanextsolutions.com/blog/using-nat-gateways-in-aws/" target="_blank">DataNext Blog Using NAT Gateways in AWS&nbsp;</a></h4><h4 style="text-align: left;"><br /><a href="https://medium.com/@zeebaig/using-nat-gateways-in-aws-455f88887143" target="_blank">Medium Blog Using NAT Gateways in AWS&nbsp;</a></h4><div><br /></div><div><a href="https://twitter.com/IamZeeshanBaig" target="_blank">@IamZeeshanBaig</a></div><div><br /><h3 style="text-align: left;">About DataNext</h3><b><div><b><br /></b></div>DataNext Solutions</b> is US based system integrator, specialized in Cloud, Big Data, DevOps technologies. As a registered AWS partner, our services comprise any Cloud Migration, Cost optimization, Integration, Security and Managed Services. <a href="http://bookings.datanextsolutions.com/">Click here and Book</a> Free assessment call with our experts today or visit our website <a href="https://www.datanextsolutions.com/">www.datanextsolutions.com</a> for more info.</div></div></div><img src="http://feeds.feedburner.com/~r/BaigsTechnologyBlogWorld/~4/YW5Gn_F9WIU" height="1" width="1" alt=""/> Zeeshan Baig tag:blogger.com,1999:blog-6974900699539223894.post-3348689330675506815 Thu Jun 21 2018 11:07:00 GMT-0400 (EDT) Load sample data model into APEX 18.1 using Quick SQL - [Video 02 - English] http://feedproxy.google.com/~r/DescubriendoElMundoDeOracle/~3/5B3Tkjix9Xo/load-sample-data-model-into-apex-181.html My new video about Oracle APEX 18.1 is live!<br /><div style="text-align: center;"><br /></div><div style="text-align: center;"><iframe allow="autoplay; encrypted-media" allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/e5rUppXLwJc" width="560"></iframe></div><img src="http://feeds.feedburner.com/~r/DescubriendoElMundoDeOracle/~4/5B3Tkjix9Xo" height="1" width="1" alt=""/> Clarisa J. Maman Orfali tag:blogger.com,1999:blog-1315583943401206186.post-3058591713955084324 Wed Jun 20 2018 20:21:00 GMT-0400 (EDT) Cargar modelo de datos de ejemplo en APEX 18.1 usando Quick SQL - [Video 02 - Español] http://feedproxy.google.com/~r/DescubriendoElMundoDeOracle/~3/4DjzBWYeOJE/cargar-modelo-de-datos-de-ejemplo-en.html Te comparto mi nuevo video tutorial! espero sea de utilidad!<br /><br /><br /><div style="text-align: center;"><br /></div><div style="text-align: center;"><iframe allow="autoplay; encrypted-media" allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/s6AeWYOhR_o" width="560"></iframe></div><img src="http://feeds.feedburner.com/~r/DescubriendoElMundoDeOracle/~4/4DjzBWYeOJE" height="1" width="1" alt=""/> Clarisa J. Maman Orfali tag:blogger.com,1999:blog-1315583943401206186.post-3149815907929410625 Wed Jun 20 2018 20:19:00 GMT-0400 (EDT) Error!?! What's going in APEX? The easiest way to Debug and Trace an Oracle APEX session http://dgielis.blogspot.com/2018/06/error-whats-going-in-apex-easiest-way.html <div class="separator" style="clear: both; text-align: left;">There are some days you just can't explain the behaviour of the APEX Builder or your own APEX Application. Or you recognize this sentence of your end-user? "Hey, it doesn't work..."</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">In Oracle APEX 5.1 and 18.1, here's how you start to see in the land of the blinds :)</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Logged in as a developer in APEX, go to Monitor Activity:</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-xGlTQyvE5eo/WyqEGvd3XOI/AAAAAAAAJKQ/SLLAyldyh0EixQm1lV5w46AR68o31_WzQCLcBGAs/s1600/Screen%2BShot%2B2018-06-19%2Bat%2B11.10.14.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="353" data-original-width="1600" height="140" src="https://1.bp.blogspot.com/-xGlTQyvE5eo/WyqEGvd3XOI/AAAAAAAAJKQ/SLLAyldyh0EixQm1lV5w46AR68o31_WzQCLcBGAs/s640/Screen%2BShot%2B2018-06-19%2Bat%2B11.10.14.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div>&nbsp;From there go to Active Sessions:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com-ZMw9J6PUjdI/WyqEGmmw_3I/AAAAAAAAJKU/DHjBSRvFRy44EY_646qIryRPVYVyPsLXgCLcBGAs/s1600/Screen%2BShot%2B2018-06-19%2Bat%2B11.11.05.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="407" data-original-width="1600" height="162" src="https://1.bp.blogspot.com/-ZMw9J6PUjdI/WyqEGmmw_3I/AAAAAAAAJKU/DHjBSRvFRy44EY_646qIryRPVYVyPsLXgCLcBGAs/s640/Screen%2BShot%2B2018-06-19%2Bat%2B11.11.05.png" width="640" /></a></div><br /><br />You will see all active sessions at that moment. Looking at the Session Id or Owner (User) you can identify the session easily:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-8s1_QhtRvJc/WyqEGz7cMOI/AAAAAAAAJKY/a2In5i-NlxYtTsIOU43riHKCPaA0sUHXwCLcBGAs/s1600/Screen%2BShot%2B2018-06-19%2Bat%2B11.11.32.png" imageanchor="1" style="margin-left: 1e