{"id":73093,"date":"2016-10-11T13:38:16","date_gmt":"2016-10-11T13:38:16","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/uncategorized\/json-for-absolute-beginners-part-5-generating-json-in-oracle\/"},"modified":"2021-07-14T13:07:00","modified_gmt":"2021-07-14T13:07:00","slug":"json-for-absolute-beginners-part-5-generating-json-in-oracle","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/oracle-databases\/json-for-absolute-beginners-part-5-generating-json-in-oracle\/","title":{"rendered":"JSON For Absolute Beginners: Part 5 \u2013 Generating JSON in Oracle"},"content":{"rendered":"<p>In this fifth article in our series on JSON and the Oracle database we\u2019ll be pulling the curtains back on the magic tricks that can convert your boring old relational data to JSON. OK, maybe that\u2019s overselling it a little. Obviously there\u2019s no magic involved; indeed some may say it\u2019s anything but.<\/p>\n<p>But before we get to all of that, if you\u2019re new to this whole JSON malarkey, you\u2019ll probably want to start from <a href=\"https:\/\/allthingsoracle.com\/json-for-absolute-beginners-part-1-introduction\/\" target=\"_blank\">Article 1<\/a> in this series and work your way back up to this point. Go on, we\u2019ll wait for you.<\/p>\n<p>As I\u2019ve intimated throughout the series, JSON &#8211; compared to, say, XML &#8211; is treated a little like the dark-haired stepchild in Oracle. And nowhere is this more apparent than when it comes to generating JSON. You probably assume that there are JSON translations for those XML stables like XMLElement, XMLForest and the rest, right?<\/p>\n<p>Wrong. If &#8211; in 2016 &#8211; you want to generate JSON from your relational data in Oracle, here\u2019s how you have to do it.<\/p>\n<h5>Building JSON Manually<\/h5>\n<p>You could, of course, roll up your sleeves and construct your JSON string manually. After all, it\u2019s just text, and so someone with your sql and pl\/sql ninja skills should be able to knock it together with minimum fuss. OK, maybe not <em>minimum<\/em> fuss, but it <em>is<\/em> possible.<\/p>\n<p>The following select statement uses a <a href=\"https:\/\/allthingsoracle.com\/anatomy-of-a-select-statement-part-1-the-with-clause\/\" target=\"_blank\">with clause<\/a> and <a href=\"https:\/\/allthingsoracle.com\/introduction-to-analytic-functions-part-1-2\/\" target=\"_blank\">analytic functions<\/a> to transform the contents of the Dept and Emp tables into JSON data.<\/p>\n<pre> WITH depts AS (SELECT '{ '\r\n                     ||' \"Department\":\"'||dname ||'\"'\r\n                     ||',\"ID\":\"'        ||deptno||'\"'\r\n                     ||',\"City\":\"'      ||loc   ||'\"'\r\n                     ||',\"Staff\":'      ||(  SELECT '['\r\n                                               ||LISTAGG('{' ||'\"Name\":\"' ||ename|| '\"'|| ',\"Job\":\"'|| job|| '\"'||',\"Salary\":'||sal||'}', ',') WITHIN GROUP (ORDER BY 1)\r\n                                               ||']' \r\n                                              FROM emp \r\n                                              WHERE emp.deptno = dept.deptno)\r\n                    ||'}' AS dept_detail\r\n               FROM dept)\r\nSELECT '{\"Organisation Structure\" : [ '\r\n    ||(SELECT LISTAGG( dept_detail, ',') WITHIN GROUP (ORDER BY 1)\r\n       FROM depts)\r\n    ||']}' organisation_json\r\nFROM DUAL ;\r\n<\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/oracle\/2016\/10\/organisation_structure_sql.jpg\" \/><\/p>\n<p>So yes, it is possible. But did you know that it\u2019s also possible to survive for a full month eating nothing but raw potatoes? I read it on the Internet so it must be true. But just because a thing is possible doesn\u2019t mean it\u2019s a good idea or even remotely practical. So no, you don\u2019t want to handcraft all your JSON data. Life\u2019s too short.<\/p>\n<h5>APEX_JSON<\/h5>\n<p>When Apex 5.0 was released back in 2015, one of the new packages was <a href=\"https:\/\/docs.oracle.com\/cd\/E59726_01\/doc.50\/e39149\/apex_json.htm#AEAPI29635\" target=\"_blank\">APEX_JSON<\/a>. The package contains, amongst other goodies, procedures that allow you build or generate valid JSON. Here are a few of the routines that I think you should know:<\/p>\n<p><strong>OPEN_OBJECT<\/strong> &#8211; writes an open curly bracket. <br \/>\n <strong>OPEN_ARRAY<\/strong> &#8211; writes an open square bracket <br \/>\n <strong>WRITE <\/strong>&#8211; overloaded procedure that writes a value. <br \/>\n <strong>CLOSE_ARRAY <\/strong>&#8211; writes a close square bracket <br \/>\n <strong>CLOSE_OBJECT <\/strong>&#8211; writes a close curly bracket <br \/>\n <strong>CLOSE_ALL <\/strong>&#8211; closes all open objects and arrays <br \/>\n <strong>INITIALIZE_CLOB_OUTPUT <\/strong>&#8211; instructs the package to write all output to a temporary clob<br \/>\n <strong>GET_CLOB_OUTPUT <\/strong>&#8211; returns the contents of the temporary clob<br \/>\n <strong>FREE_OUTPUT <\/strong>&#8211; call this after get_clob_output to free the output resources.<\/p>\n<p>You can probably guess how these procedures work and how to use them, but since you\u2019re here and I\u2019m here I might as well patronise you with two examples &#8211; one in which we construct the JSON string manually, and a second using a weak ref cursor. Let\u2019s return to the dept and emp tables.<\/p>\n<pre>BEGIN\r\n  \r\n APEX_JSON.INITIALIZE_CLOB_OUTPUT;\r\n APEX_JSON.OPEN_OBJECT;\r\n APEX_JSON.OPEN_OBJECT('Organisation Structure');\r\n APEX_JSON.OPEN_ARRAY;\r\n FOR i IN (SELECT *\r\n           FROM dept) LOOP\r\n\r\n          APEX_JSON.OPEN_OBJECT;\r\n          APEX_JSON.WRITE('Department',i.dname);\r\n          APEX_JSON.WRITE('ID',i.deptno);\r\n          APEX_JSON.WRITE('City',i.loc);\r\n          APEX_JSON.OPEN_ARRAY('Staff');\r\n\r\n          FOR j IN (SELECT *\r\n                    FROM emp\r\n                    WHERE emp.deptno = i.deptno) LOOP\r\n\r\n                    APEX_JSON.OPEN_OBJECT;\r\n                    APEX_JSON.WRITE('Name',j.ename);\r\n                    APEX_JSON.WRITE('Job',j.job);\r\n                    APEX_JSON.WRITE('Salary',j.sal);\r\n                    APEX_JSON.CLOSE_OBJECT;\r\n          END LOOP;\r\n          APEX_JSON.CLOSE_ARRAY;\r\n          APEX_JSON.CLOSE_OBJECT;\r\n  END LOOP;\r\n  APEX_JSON.CLOSE_ALL;\r\n\r\n  DBMS_OUTPUT.PUT_LINE(APEX_JSON.GET_CLOB_OUTPUT);\r\n  APEX_JSON.FREE_OUTPUT;\r\nEND;\r\n\/\r\n<\/pre>\n<p>Or, if you wanted to produce the same output a little less manually, you could use a ref cursor.<\/p>\n<pre>DECLARE\r\n  l_cur SYS_REFCURSOR;\r\nBEGIN\r\n  \r\n  OPEN l_cur FOR\r\n    SELECT dname \"Department\",\r\n           deptno \"ID\",\r\n           loc \"City\",\r\n           CURSOR(SELECT ename \"Name\",\r\n                         job \"Job\",\r\n                         sal \"Salary\"\r\n                  FROM   emp \r\n                  WHERE  emp.deptno = dept.deptno ) AS \"Staff\"\r\n    FROM   dept \r\n    ORDER BY dname;\r\n\r\n  APEX_JSON.INITIALIZE_CLOB_OUTPUT;\r\n\r\n  APEX_JSON.OPEN_OBJECT;\r\n  APEX_JSON.WRITE('Organisation Structure', l_cur);\r\n  APEX_JSON.CLOSE_OBJECT;\r\n\r\n  DBMS_OUTPUT.PUT_LINE(APEX_JSON.GET_CLOB_OUTPUT);\r\n  APEX_JSON.FREE_OUTPUT;\r\nEND;\r\n\/\r\n<\/pre>\n<p>Depending on your preferences, where your SQL strengths lie and your particular requirement, either of these methods should work for you. It\u2019s all as straightforward as peeling a banana. But\u2026<\/p>\n<p>Well, APEX_JSON comes bundled with Apex from version 5.0, so if you don\u2019t have Application Express installed, or if, for whatever reason, you have decided not to upgrade to Release 5, then you\u2019re out of luck. Which means you have to return to the Stone Ages and to chiselling your JSON data using crude tools like concatenation and analytical functions.<\/p>\n<p>Unless there\u2019s another way\u2026<\/p>\n<h5>PL\/JSON<\/h5>\n<p>There is, and it\u2019s called <a href=\"https:\/\/github.com\/pljson\/pljson\" target=\"_blank\">PL\/JSON<\/a>. PL\/JSON is an open source suite of packages that, once installed, gives you the ability to generate JSON data. And while it might not match APEX_JSON when it comes to simplicity, it is not a million miles from it in the way it goes about solving problems.<\/p>\n<p>It has two object types &#8211; <em>JSON <\/em>for objects and <em>JSON_LIST <\/em>for arrays &#8211; and a number of procedures that allow you manipulate your instances of these objects, once you\u2019ve created them. Chief amongst those procedures is <em>put<\/em>, which unsurprisingly is the analog of APEX_JSON\u2019s <em>write <\/em>procedure.<\/p>\n<p>This is the point at which I would usually furnish you with an example, reproducing the JSON data from our previous sections using PL\/JSON. However, Dan McGhan has pretty much done the work for me in <a href=\"https:\/\/jsao.io\/2015\/07\/relational-to-json-with-pljson\/\" target=\"_blank\">a blogpost<\/a> he has written so I might as well point you in that direction.<\/p>\n<p>PL\/JSON is quite popular and, until the advent of APEX_JSON, was probably the premier way of working with JSON in the Oracle database. It comes with a large number of example files, but no further documentation, and so you have to be ready to hack through the thicket of trial-and-error if you wish to learn it.<\/p>\n<p>Ouch.<\/p>\n<h5>Oracle 12.2<\/h5>\n<p>But, you know what? None of that should matter for very long. And that is because Oracle 12c Release 2 (planned for late 2016) promises to fill the gap we\u2019ve been talking about with a slate of new <a href=\"https:\/\/docs.oracle.com\/cloud\/latest\/db122\/ADJSN\/generation.htm#ADJSN-GUID-C0F8F837-EE36-4EDD-9261-6E8A9245906C\" target=\"_blank\">SQL\/JSON functions for generating JSON data<\/a>. The functions &#8211; <em>json_object, json_array, json_objectagg,<\/em> and <em>json_arrayagg<\/em> &#8211; they say, will be easy to use, and lightweight.<\/p>\n<p>All of which means that in a few short months, I might have to rewrite this whole article. But, you know what, if the new functionality lives up to its promise, I\u2019ll do it with a smile on my face.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this fifth article in our series on JSON and the Oracle database we\u2019ll be pulling the curtains back on the magic tricks that can convert your boring old relational data to JSON. OK, maybe that\u2019s overselling it a little. Obviously there\u2019s no magic involved; indeed some may say it\u2019s anything but. But before we get to all of that,&hellip;<\/p>\n","protected":false},"author":221907,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143533],"tags":[48355,4880,48457,48473],"coauthors":[],"class_list":["post-73093","post","type-post","status-publish","format-standard","hentry","category-oracle-databases","tag-apex_json","tag-json","tag-oracle-12c-release-2","tag-pljson"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/73093","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221907"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=73093"}],"version-history":[{"count":1,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/73093\/revisions"}],"predecessor-version":[{"id":91594,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/73093\/revisions\/91594"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=73093"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=73093"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=73093"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=73093"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}