{"id":614,"date":"2016-06-15T08:25:14","date_gmt":"2016-06-15T08:25:14","guid":{"rendered":"http:\/\/bar-solutions.com\/weblog\/?p=614"},"modified":"2016-06-15T08:25:55","modified_gmt":"2016-06-15T08:25:55","slug":"use-the-database-to-do-the-heavy-lifting","status":"publish","type":"post","link":"https:\/\/blog.bar-solutions.com\/?p=614","title":{"rendered":"Use the database to do the heavy lifting"},"content":{"rendered":"<p>Suppose you have data in your PL\/SQL program stored in a collection. I am using the EMP table (14 records) but you should imagine you have many, many more records in your collection. If you want to order (sort) your collection in a different manner somewhere in your code you can of course write your own sorting routine but the <a title=\"Oracle\" href=\"http:\/\/www.oracle.com\/\" target=\"_blank\" rel=\"nofollow\">Oracle<\/a> database is doing this for ages and probably a lot smarter (after all these years) than you can ever do it.<\/p>\n<p><!--more--><\/p>\n<p>If you are running an Oracle pre 12c database you can use the SQL-engine when you have your data in a Nested Table. I have created this little test script to try this. Again, the EMP table has only 14 records defined, but it is used to drive the point home.<\/p>\n<div class=\"code\" align=\"left\">\n<pre><span class=\"kwrd\">CREATE OR REPLACE TYPE<\/span> emp_t <span class=\"kwrd\">AS<\/span> <span class=\"kwrd\">OBJECT<\/span>\r\n( empno <span class=\"kwrd\">number<\/span>(<span class=\"str\">4<\/span>)\r\n, ename <span class=\"kwrd\">varchar2<\/span>(<span class=\"str\">10<\/span>)\r\n, job <span class=\"kwrd\">varchar2<\/span>(<span class=\"str\">9<\/span>)\r\n, mgr <span class=\"kwrd\">number<\/span>(<span class=\"str\">4<\/span>)\r\n, hiredate <span class=\"kwrd\">DATE<\/span>\r\n, sal <span class=\"kwrd\">number<\/span>(<span class=\"str\">7<\/span>,<span class=\"str\">2<\/span>)\r\n, comm <span class=\"kwrd\">number<\/span>(<span class=\"str\">7<\/span>,<span class=\"str\">2<\/span>)\r\n, deptno <span class=\"kwrd\">number<\/span>(<span class=\"str\">2<\/span>)\r\n)<\/pre>\n<\/div>\n<div class=\"code\" align=\"left\">\n<pre><span class=\"kwrd\">CREATE OR REPLACE TYPE<\/span> emp_ntt <span class=\"kwrd\">AS<\/span> <span class=\"kwrd\">TABLE<\/span> <span class=\"kwrd\">OF<\/span> emp_t<\/pre>\n<\/div>\n<div class=\"code\" align=\"left\">\n<pre><span class=\"kwrd\">CREATE OR REPLACE PACKAGE<\/span> emp_test <span class=\"kwrd\">IS<\/span>\r\n  <span class=\"kwrd\">FUNCTION<\/span> get_emp <span class=\"kwrd\">RETURN<\/span> emp_ntt;\r\n  <span class=\"kwrd\">PROCEDURE<\/span> emp_prc;\r\n<span class=\"kwrd\">END<\/span>;<\/pre>\n<\/div>\n<div class=\"code\" align=\"left\">\n<pre><span class=\"kwrd\">CREATE OR REPLACE PACKAGE<\/span> <span class=\"kwrd\">BODY<\/span> emp_test <span class=\"kwrd\">IS<\/span>\r\n  <span class=\"kwrd\">PROCEDURE<\/span> separator\r\n  <span class=\"kwrd\">IS<\/span>\r\n  <span class=\"kwrd\">BEGIN<\/span>\r\n    dbms_output.put_line('<span class=\"str\">-=-=-=-=-<\/span>');\r\n  <span class=\"kwrd\">END<\/span>;\r\n<span class=\"rem\">--<\/span>\r\n  <span class=\"kwrd\">FUNCTION<\/span> get_emp <span class=\"kwrd\">RETURN<\/span> emp_ntt\r\n  <span class=\"kwrd\">IS<\/span>\r\n    l_returnvalue emp_ntt;\r\n  <span class=\"kwrd\">CURSOR<\/span> c_emp <span class=\"kwrd\">IS<\/span>\r\n  <span class=\"kwrd\">SELECT<\/span> emp_t(empno, ename, job, mgr, hiredate, sal, comm, deptno)\r\n    <span class=\"kwrd\">FROM<\/span> emp;\r\n  <span class=\"kwrd\">BEGIN<\/span>\r\n    <span class=\"kwrd\">OPEN<\/span> c_emp;\r\n    <span class=\"kwrd\">FETCH<\/span> c_emp <span class=\"kwrd\">BULK<\/span> <span class=\"kwrd\">COLLECT<\/span> <span class=\"kwrd\">INTO<\/span> l_returnvalue;\r\n    <span class=\"kwrd\">CLOSE<\/span> c_emp;\r\n    <span class=\"kwrd\">RETURN<\/span> l_returnvalue;\r\n  <span class=\"kwrd\">END<\/span>;\r\n<span class=\"rem\">--<\/span>\r\n  <span class=\"kwrd\">PROCEDURE<\/span> emp_prc <span class=\"kwrd\">IS<\/span>\r\n    l_emps emp_ntt;\r\n    l_emps_sorted emp_ntt;\r\n    <span class=\"kwrd\">CURSOR<\/span> c_emp_sort(emps_in emp_ntt)\r\n    <span class=\"kwrd\">IS<\/span>\r\n    <span class=\"kwrd\">SELECT<\/span> emp_t(empno, ename, job, mgr, hiredate, sal, comm, deptno)\r\n      <span class=\"kwrd\">FROM<\/span> table(emps_in)\r\n     <span class=\"kwrd\">ORDER<\/span> <span class=\"kwrd\">BY<\/span> ename;\r\n  <span class=\"kwrd\">BEGIN<\/span>\r\n    l_emps := get_emp;\r\n    <span class=\"kwrd\">FOR<\/span> rec <span class=\"kwrd\">IN<\/span> (select ename <span class=\"kwrd\">FROM<\/span> table(l_emps)) loop\r\n      dbms_output.put_line(rec.ename);\r\n    <span class=\"kwrd\">END<\/span> loop;\r\n<span class=\"rem\">--<\/span>\r\n    separator;\r\n<span class=\"rem\">--<\/span>\r\n    <span class=\"kwrd\">OPEN<\/span> c_emp_sort(l_emps);\r\n    <span class=\"kwrd\">FETCH<\/span> c_emp_sort <span class=\"kwrd\">BULK<\/span> <span class=\"kwrd\">COLLECT<\/span> <span class=\"kwrd\">INTO<\/span> l_emps_sorted;\r\n    <span class=\"kwrd\">CLOSE<\/span> c_emp_sort;\r\n    <span class=\"kwrd\">FOR<\/span> indx <span class=\"kwrd\">IN<\/span> l_emps_sorted.first .. l_emps_sorted.last loop\r\n      dbms_output.put_line(l_emps_sorted(indx).ename);\r\n    <span class=\"kwrd\">END<\/span> loop;\r\n  <span class=\"kwrd\">END<\/span>;\r\n<span class=\"kwrd\">END<\/span>;<\/pre>\n<\/div>\n<p>If I run this code<\/p>\n<div class=\"code\" align=\"left\">\n<pre><span class=\"kwrd\">EXEC<\/span> emp_test.emp_prc<\/pre>\n<\/div>\n<p>the output looks like this:<\/p>\n<div class=\"code\" align=\"left\">\n<pre>SMITH\r\nALLEN \r\nWARD \r\nJONES \r\nMARTIN \r\nBLAKE \r\nCLARK \r\nSCOTT \r\nKING \r\nTURNER \r\nADAMS \r\nJAMES \r\nFORD \r\nMILLER \r\n-=-=-=-=- \r\nADAMS \r\nALLEN \r\nBLAKE \r\nCLARK \r\nFORD \r\nJAMES \r\nJONES \r\nKING \r\nMARTIN \r\nMILLER \r\nSCOTT \r\nSMITH \r\nTURNER \r\nWARD<\/pre>\n<\/div>\n<p>This is a great way of using the SQL engine to do the work you need done.<\/p>\n<p>But what if you don&#8217;t have your data in a Nested Table, but in an Associative Array, which is PL\/SQL only. If you are using Database 12c you&#8217;re in luck, because you can now use your Associative Array in de SQL statement.<\/p>\n<p>I have created a similar script as the one before, except that I cannot define a TYPE in the SQL layer, it should be defined in a package specification.<\/p>\n<div class=\"code\" align=\"left\">\n<pre><span class=\"kwrd\">PACKAGE<\/span> emp_test <span class=\"kwrd\">IS<\/span>\r\n  <span class=\"kwrd\">TYPE<\/span> emp_aat <span class=\"kwrd\">IS<\/span> <span class=\"kwrd\">TABLE<\/span> <span class=\"kwrd\">OF<\/span> emp%rowtype <span class=\"kwrd\">INDEX<\/span> <span class=\"kwrd\">BY<\/span> <span class=\"kwrd\">PLS_INTEGER<\/span>;\r\n  <span class=\"kwrd\">FUNCTION<\/span> get_emp <span class=\"kwrd\">RETURN<\/span> emp_aat;\r\n  <span class=\"kwrd\">PROCEDURE<\/span> emp_prc;\r\n<span class=\"kwrd\">END<\/span>;<\/pre>\n<\/div>\n<div class=\"code\" align=\"left\">\n<pre><span class=\"kwrd\">PACKAGE<\/span> <span class=\"kwrd\">BODY<\/span> emp_test <span class=\"kwrd\">IS<\/span>\r\n  <span class=\"kwrd\">PROCEDURE<\/span> separator\r\n  <span class=\"kwrd\">IS<\/span>\r\n  <span class=\"kwrd\">BEGIN<\/span>\r\n    dbms_output.put_line('<span class=\"str\">-=-=-=-=-<\/span>');\r\n  <span class=\"kwrd\">END<\/span>;\r\n<span class=\"rem\">--<\/span>\r\n  <span class=\"kwrd\">FUNCTION<\/span> get_emp <span class=\"kwrd\">RETURN<\/span> emp_aat\r\n  <span class=\"kwrd\">IS<\/span>\r\n  l_returnvalue emp_aat;\r\n  <span class=\"kwrd\">CURSOR<\/span> c_emp <span class=\"kwrd\">IS<\/span>\r\n  <span class=\"kwrd\">SELECT<\/span> *\r\n    <span class=\"kwrd\">FROM<\/span> emp;\r\n  <span class=\"kwrd\">BEGIN<\/span>\r\n    <span class=\"kwrd\">OPEN<\/span> c_emp;\r\n    <span class=\"kwrd\">FETCH<\/span> c_emp <span class=\"kwrd\">BULK<\/span> <span class=\"kwrd\">COLLECT<\/span> <span class=\"kwrd\">INTO<\/span> l_returnvalue;\r\n    <span class=\"kwrd\">CLOSE<\/span> c_emp;\r\n    <span class=\"kwrd\">RETURN<\/span> l_returnvalue;\r\n  <span class=\"kwrd\">END<\/span>;\r\n<span class=\"rem\">--<\/span>\r\n  <span class=\"kwrd\">PROCEDURE<\/span> emp_prc <span class=\"kwrd\">IS<\/span>\r\n    l_emps emp_aat;\r\n    l_emps_sorted emp_aat;\r\n    <span class=\"kwrd\">CURSOR<\/span> c_emp_sort(emps_in emp_aat)\r\n    <span class=\"kwrd\">IS<\/span>\r\n    <span class=\"kwrd\">SELECT<\/span> *\r\n      <span class=\"kwrd\">FROM<\/span> table(emps_in)\r\n     <span class=\"kwrd\">ORDER<\/span> <span class=\"kwrd\">BY<\/span> ename;\r\n  <span class=\"kwrd\">BEGIN<\/span>\r\n    l_emps := get_emp;\r\n    <span class=\"kwrd\">FOR<\/span> rec <span class=\"kwrd\">IN<\/span> (select ename <span class=\"kwrd\">FROM<\/span> <span class=\"kwrd\">TABLE<\/span>(l_emps)) <span class=\"kwrd\">LOOP<\/span>\r\n      dbms_output.put_line(rec.ename);\r\n    <span class=\"kwrd\">END<\/span> <span class=\"kwrd\">LOOP<\/span>;\r\n<span class=\"rem\">--<\/span>\r\n    separator;\r\n<span class=\"rem\">--<\/span>\r\n    <span class=\"kwrd\">OPEN<\/span> c_emp_sort(l_emps);\r\n    <span class=\"kwrd\">FETCH<\/span> c_emp_sort <span class=\"kwrd\">BULK<\/span> <span class=\"kwrd\">COLLECT<\/span> <span class=\"kwrd\">INTO<\/span> l_emps_sorted;\r\n    <span class=\"kwrd\">CLOSE<\/span> c_emp_sort;\r\n    <span class=\"kwrd\">FOR<\/span> indx <span class=\"kwrd\">IN<\/span> l_emps_sorted.first .. l_emps_sorted.last <span class=\"kwrd\">LOOP<\/span>\r\n      dbms_output.put_line(l_emps_sorted(indx).ename);\r\n    <span class=\"kwrd\">END<\/span> <span class=\"kwrd\">LOOP<\/span>;\r\n  <span class=\"kwrd\">END<\/span>;\r\n<span class=\"kwrd\">END<\/span>;<\/pre>\n<\/div>\n<p>If I run this code on my 11Gr2 database it results in the following error:<\/p>\n<div class=\"code\" align=\"left\">\n<pre>No errors for PACKAGE DEMO.EMP_TEST \r\n<span class=\"rem\">Warning: Package body created with compilation errors <\/span>\r\nErrors for PACKAGE BODY DEMO.EMP_TEST: \r\nLINE\/COL ERROR \r\n-------- --------------------------------------------------------------------------- \r\n27\/5 PL\/SQL: SQL Statement ignored \r\n28\/12 PL\/SQL: ORA-22905: cannot access rows from a non-nested table item \r\n28\/18 PLS-00382: expression is of wrong type \r\n33\/17 PL\/SQL: SQL Statement ignored \r\n33\/35 PL\/SQL: ORA-22905: cannot access rows from a non-nested table item \r\n33\/41 PLS-00382: expression is of wrong type \r\n34\/7 PL\/SQL: Statement ignored \r\n34\/28 PLS-00364: loop index variable 'REC' use is invalid<\/pre>\n<\/div>\n<p>As mentioned before, you cannot access an Associative Array in the SQL layer. To use the SQL layer anyway you can of course create the necessary objects (record type and nested table type), copy all the data from the Associative Array to a Nested Table, run the SQL statement and copy the results back to an Associative Array. This means a lot of coding and the risk of errors. But if I run the same code on my 12Cr1 database, it completes successfully and displays the following result:<\/p>\n<div class=\"code\" align=\"left\">\n<pre>SMITH \r\nALLEN \r\nWARD \r\nJONES \r\nMARTIN \r\nBLAKE \r\nCLARK \r\nSCOTT \r\nKING \r\nTURNER \r\nADAMS \r\nJAMES \r\nFORD \r\nMILLER \r\n-=-=-=-=- \r\nADAMS \r\nALLEN \r\nBLAKE \r\nCLARK \r\nFORD \r\nJAMES \r\nJONES \r\nKING \r\nMARTIN \r\nMILLER \r\nSCOTT \r\nSMITH \r\nTURNER \r\nWARD<\/pre>\n<\/div>\n<p>I think Oracle does a good job extending the possibilities of the PL\/SQL language, especially integrating to SQL features into the PL\/SQL layer. Although this might look like a small enhancement, but it can have a big impact on the performance of your program.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Suppose you have data in your PL\/SQL program stored in a collection. I am using the EMP table (14 records) but you should imagine you have many, many more records in your collection. If you want to order (sort) your collection in a different manner somewhere in your code you can of course write your [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,5,9],"tags":[],"class_list":["post-614","post","type-post","status-publish","format-standard","hentry","category-oracle","category-plsql","category-sql"],"_links":{"self":[{"href":"https:\/\/blog.bar-solutions.com\/index.php?rest_route=\/wp\/v2\/posts\/614","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.bar-solutions.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.bar-solutions.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.bar-solutions.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.bar-solutions.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=614"}],"version-history":[{"count":3,"href":"https:\/\/blog.bar-solutions.com\/index.php?rest_route=\/wp\/v2\/posts\/614\/revisions"}],"predecessor-version":[{"id":669,"href":"https:\/\/blog.bar-solutions.com\/index.php?rest_route=\/wp\/v2\/posts\/614\/revisions\/669"}],"wp:attachment":[{"href":"https:\/\/blog.bar-solutions.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=614"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.bar-solutions.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=614"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.bar-solutions.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=614"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}