{"id":73101,"date":"2016-09-16T15:54:41","date_gmt":"2016-09-16T15:54:41","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/uncategorized\/json-for-absolute-beginners-part-3-storing-json-in-oracle\/"},"modified":"2021-07-14T13:07:02","modified_gmt":"2021-07-14T13:07:02","slug":"json-for-absolute-beginners-part-3-storing-json-in-oracle","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/oracle-databases\/json-for-absolute-beginners-part-3-storing-json-in-oracle\/","title":{"rendered":"JSON For Absolute Beginners: Part 3 &#8211; Storing JSON in Oracle"},"content":{"rendered":"<p>Welcome to part three in this series of articles about Oracle and its uneasy romance with JSON. Uneasy? Well, that\u2019s a bit of a spoiler; so far it&#8217;s been smooth sailing. <a href=\"https:\/\/allthingsoracle.com\/json-for-absolute-beginners-part-1-introduction\/\">Part 1<\/a> was a precis of JSON, while <a href=\"https:\/\/allthingsoracle.com\/json-for-absolute-beginners-part-2-why-use-oracle\/\">Part 2 <\/a>delved into the reasons for Oracle\u2019s involvement in the area. So far so good; but now we\u2019ve got to talk <em>how<\/em>.<\/p>\n<p>In other words &#8211; and to (over)stretch the romance analogy &#8211; we\u2019ve introduced our main characters, they\u2019ve fallen in love, and now we\u2019re approaching the scene where they have a big fight and JSON screams, \u201cYou don\u2019t care about me! You don\u2019t do for me the things you do for \u2026 <em>her<\/em>.\u201d<\/p>\n<p>\u201cWho?\u201d<\/p>\n<p>\u201cYour ex, XML!\u201d<\/p>\n<p>Aargh, stop me before I get carried away; this is a technical document, not a romance novel.<\/p>\n<p>However, there\u2019s a serious point buried in all that fluff; Oracle\u2019s offering for JSON pales in comparison to their robust suite of XML functionality. But let\u2019s not get ahead of ourselves; there\u2019s still a huge amount to learn. Let\u2019s start at the start: storing JSON in an Oracle database.<\/p>\n<h5>Storing JSON Data<\/h5>\n<blockquote>\n<p>\u201cYou don\u2019t do for me the things you do for her \u2026 for XML!\u201d<\/p>\n<\/blockquote>\n<p>Unlike XML which has its own personal data type &#8211; XMLType &#8211; there isn\u2019t a specific data type dedicated solely to JSON data. It is recommended that you store your JSON documents in either a VARCHAR2 column, a CLOB or a BLOB.<\/p>\n<p>JSON documents, you will recall, are stored wholesale and not broken down into their atomic values in the way that good normalization would have us do with relational data. To that end, you may have a table &#8211; let\u2019s call ours <em>json_test\u00a0&#8211;\u00a0<\/em>with an ID column, and you\u2019d want a second column to store your JSON data in. So which do you choose &#8211; VARCHAR2, CLOB or BLOB?<\/p>\n<p>There are a few differences. The difference between VARCHAR2 and CLOB, as you know, is size. Take the size of your JSON documents into account when choosing between the two. However, you should know that Oracle uses UTF-8 when processing JSON data. This means that if your data is not UTF-8 it will carry out automatic character-set conversion. If this is something that you wish to guard against you may want to store your JSON data in a BLOB, which doesn\u2019t store JSON textually, and therefore is never converted.<\/p>\n<p>One final point on the topic: if you decide to store your JSON data in a BLOB, you\u2019ll need to inform Oracle that it is JSON data each time you process it by using the FORMAT JSON keyphrase. More on that later.<\/p>\n<p>But for now, let\u2019s build that table we talked about, <em>json_test<\/em>.<\/p>\n<pre>CREATE TABLE json_test\r\n(ID            RAW(16) NOT NULL,\r\n json_data     CLOB    NOT NULL,\r\n created_date  DATE    DEFAULT SYSDATE\r\n);\r\n<\/pre>\n<h5>Check Constraints<\/h5>\n<p>So here\u2019s a question. If we\u2019re putting our JSON data in a bog-standard VARCHAR2 column or CLOB and don\u2019t have the protection of an XMLType kind of data type, what\u2019s to stop us from accidentally storing other types of data in the same column? The clever bods at Oracle have thought of that, and have introduced two new JSON conditions: <em>is json<\/em> and <em>is not json<\/em>. These conditions can be used in case statements and in where clauses, but it is very important that we also use <em>is json<\/em> in check constraints on columns designed to hold JSON data. Let me show you.<\/p>\n<pre>ALTER TABLE json_test\r\nADD CONSTRAINT check_is_json\r\n CHECK (json_data IS JSON);\r\n<\/pre>\n<p>If you trust your data source and are aware that check constraints sometimes come with a performance cost, you might be tempted to forgo the constraint. Don\u2019t. In addition to acting as bouncers at your data\u2019s door, these check constraints also inform Oracle that this column contains JSON data. To this end there are a number of new data dictionary views: <a href=\"https:\/\/docs.oracle.com\/database\/121\/REFRN\/GUID-0FEC03C4-8F07-47C0-8FC0-A771EBF5D057.htm#REFRN20963\" target=\"_blank\">ALL_JSON_COLUMNS<\/a>, DBA_JSON_COLUMNS and USER_JSON_COLUMNS that pick up all columns that have an <em>is json<\/em> check constraint. If you drop your check constraint your column will disappear from these views; however if you only <em>disable<\/em> it the column will still be picked up by the data dictionary.<\/p>\n<p>(You may have noticed that I\u2019ve not said anything about the <em>is not json<\/em> condition. It obviously doesn\u2019t make any sense to use it in our check constraints; however, as I\u2019ve said, these conditions can both be used in other ways too. Let\u2019s put <em>is not json<\/em> out of our minds for now; we\u2019ll return to it in the next article in this series when we discuss using these conditions in where clauses.)<\/p>\n<h5>Strict vs Lax Syntax<\/h5>\n<p>Remember back when you were a teenager and you had this friend whose parents were a little more laidback than everyone else\u2019s. They\u2019d let you drink beer in their house, and they wouldn\u2019t tell you off when you road-tested a swear word in their presence. Well, Oracle is a bit like those parents when it comes to policing JSON syntax. By default, Oracle\u2019s syntax for JSON is lax. What this means is that it\u2019s not fussed about certain syntax rules.<\/p>\n<ul>\n<li>The rule is that JSON fields and strings must be enclosed in double quotation marks? Oracle\u2019ll let you use single quotes.<\/li>\n<li>The rule is that Booleans &#8211; <em>true, false, null<\/em> &#8211; must be in lowercase? Oracle\u2019ll let you use wHaTEver CasE YoU waNT.<\/li>\n<\/ul>\n<p>There are other features of <a href=\"https:\/\/docs.oracle.com\/database\/121\/ADXDB\/json.htm#GUID-1B6CFFBE-85FE-41DD-BA14-DD1DE73EAB20\" target=\"_blank\">Oracle\u2019s lax JSON syntax policing<\/a>, and, if you\u2019re like me you\u2019re probably thankful for it. However, you may, in certain instances, want your JSON to abide by a strict syntax. To do this you can use the STRICT keyword with the <em>is json<\/em> condition. This will tell Oracle to test if JSON data is well-formed using strict rules.<\/p>\n<pre>ALTER TABLE json_test\r\nADD CONSTRAINT check_is_json\r\n CHECK (json_data IS JSON (STRICT));\r\n<\/pre>\n<p>Please note that STRICT must be enclosed in brackets.<\/p>\n<h5>Unique Object Member Names<\/h5>\n<p>We\u2019ve established that JSON is not fussy about certain rules. For example, the following is &#8211; understandably &#8211; valid JSON data:<\/p>\n<pre>{\r\n \"firstname\"   :\"David\",\r\n \"middlename\"  :\"Dozie\",\r\n \"lastname\"    :\"Njoku\",\r\n \"occupation\"  :\"Software developer\",\r\n \"gender\"      :\"Male\"\r\n}<\/pre>\n<p>However, the following is <em>also <\/em>completely valid JSON data, despite its obvious problem:<\/p>\n<pre>{\r\n \"name\"       :\"David\",\r\n \"name\"       :\"Dozie\",\r\n \"lastname\"   :\"Njoku\",\r\n \"occupation\" :\"Software developer\",\r\n \"gender\"     :\"Male\"\r\n}\r\n<\/pre>\n<p>Whilst it is obviously unwise to have two fields with the exact same name within the exact same object, it does not violate any rules. If, however, you wish to enforce uniqueness amongst an object\u2019s members\u2019 names you can use the WITH UNIQUE KEYS key phrase with the <em>is json<\/em> condition. (You can also use WITHOUT UNIQUE KEYS. But since this is the default behaviour there\u2019s no real need to waste your energy typing out the words.)<\/p>\n<pre>ALTER TABLE json_test\r\nADD CONSTRAINT check_is_json\r\n CHECK (json_data IS JSON WITH UNIQUE KEYS);\r\n<\/pre>\n<p>It is worth bearing in mind that the WITH UNIQUE KEYS clause does come with a performance pricetag as the whole document will need to be loaded into memory before the check for duplicates can be carried out. To be honest with you, it\u2019s not a check that I use myself; however, it\u2019s probably useful that you know about it in case you ever need it.<\/p>\n<h5>Conclusion<\/h5>\n<p>So finally we are in a position where we can load our JSON data into our Oracle database: we\u2019ve created our table and applied a check constraint to ensure that our JSON is well-formed.<\/p>\n<pre>INSERT INTO json_test (id, json_data)\r\nVALUES (sys_guid(),\r\n '{\r\n  \"father\":  {\r\n   \t\t \"firstname\"   :\"David\",\r\n                 \"lastname\"    :\"Njoku\",\r\n   \t\t \"occupation\"  :\"Software developer\",\r\n   \t \t \"gender\"      :\"Male\",\r\n   \t\t \"isAdult\"     :true\r\n  \t      },\r\n  \"mother\": {\r\n   \t\t \"firstname\"   :\"Sola\",\r\n                 \"lastname\"    :\"Njoku\",\r\n   \t\t \"occupation\"  :\"Radio producer\",\r\n   \t \t \"gender\"      :\"Female\",\r\n   \t\t \"isAdult\"     :true\r\n  \t      },\r\n  \"child\":   {\r\n   \t\t \"firstname\"   :\"Moyo\",\r\n                 \"lastname\"    :\"Njoku\",\r\n   \t\t \"occupation\"  :null,\r\n   \t \t \"gender\"      :\"Male\",\r\n   \t\t \"isAdult\"     :false\r\n  \t      }\r\n}'\r\n);\r\n<\/pre>\n<p>In the next article in this series we\u2019ll take a look at the functionality that exists for querying our data.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Welcome to part three in this series of articles about Oracle and its uneasy romance with JSON. Uneasy? Well, that\u2019s a bit of a spoiler; so far it&#8217;s been smooth sailing. Part 1 was a precis of JSON, while Part 2 delved into the reasons for Oracle\u2019s involvement in the area. So far so good; but now we\u2019ve got to&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":[4880],"coauthors":[],"class_list":["post-73101","post","type-post","status-publish","format-standard","hentry","category-oracle-databases","tag-json"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/73101","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=73101"}],"version-history":[{"count":1,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/73101\/revisions"}],"predecessor-version":[{"id":91600,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/73101\/revisions\/91600"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=73101"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=73101"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=73101"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=73101"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}