23. Juli 2014

Oracle 12.1.0.2 ist da: Ein Einblick in die JSON-Unterstützung

Oracle 12.1.0.2 is here: First look into SQL JSON support
Seit kurzem ist das Patchset 12.1.0.2 der Oracle-Datenbank verfügbar. Und wie schon in der Vergangenheit ist dies mehr als nur ein Patchset: Es führt einige neue Funktionen ein.
  • Oracle In-Memory Database
  • Native Unterstützung für JSON
  • Approximage COUNT DISTINCT
  • :
In diesem Blog-Posting möchte ich euch einen kleinen Einblick in die JSON-Unterstützung geben - denn nun bietet die Oracle-Datenbank eine JSON-Unterstützung direkt auf SQL-Ebene an. Im ersten Release werden SQL-Abfragen auf JSON-Daten unterstützt, das Erzeugen von JSON oder die Unterstützung von JSON in PL/SQL stehen noch aus. Was JSON genau ist, werde ich hier jedoch nicht erläutern, dieser Wikipedia-Artikel sollte einen hinreichenden Einblick geben.
Am Anfang steht wie immer eine Tabelle mit einer Spalte, welche die JSON-Daten aufnehmen soll. Im Gegensatz zur XML-Unterstützung wurde für JSON jedoch kein eigener Datentyp eingeführt: JSON kann als BLOB, CLOB, VARCHAR2 oder NVARCHAR2 abgelegt werden - die im folgenden besprochenen SQL-Funktionen arbeiten mit allen diesen Datentypen. Das Erstellen der Tabelle ist also ganz leicht ...
create table tab_json (
  id           number        generated always as identity,
  name         varchar2(200),
  json_data   clob
)
/ 
Und in diese Tabelle können nun Daten eingefügt werden. Wir wollen mal eine Zeile mit "validem" JSON erzeugen und eine mit "Schrott" ...
insert into tab_json (name, json_data) values (
  '1. JSON', 
  '{person: {firstname: "Carsten", lastname: "Czarski", year: 2014}}'
)
/

insert into tab_json (name, json_data) values (
  '2. kein JSON, sondern XML', 
  '<person><firstname>Carsten</firstname><lastname>Czarski</lastname><year>2014</year></person>'
)
/

insert into tab_json (name, json_data) values (
  '3. wieder JSON',
  '{person: [{firstname: "Carsten", lastname: "Czarski", year: 2014}, {firstname: "John", lastname: "Doe", year: 2015}]}'
)
/

commit
/
Nun wollen wir mit den Daten arbeiten. Bevor man irgendwelche JSON-Funktionen anwendet, muss man natürlich wissen, welche Zeile JSON ist und welche nicht. Dazu dienen die SQL-Erweiterungen IS JSON bzw. IS NOT JSON.
select name from tab_json where json_data is json
/

NAME
---------------------------------------------
1. JSON
3. wieder JSON

2 Zeilen ausgewählt.

select name from tab_json where json_data is not json
/

NAME
--------------------------------------------
2. kein JSON, sondern XML

1 Zeile wurde ausgewählt.
Natürlich lässt sich mit IS JSON auch ein Check-Constraint einrichten - damit lässt sich sicherstellen, dass die Tabellenspalte tatsächlich nur JSON enthalten wird. Das setzen wir im folgenden gleich einmal um. Zuerst löschen wir die Zeile, die kein JSON ist und dann erzeugen wir den Check-Constraint.
SQL> delete from tab_json where name = '2. kein JSON, sondern XML';

1 Zeile wurde gelöscht.

SQL> alter table tab_json add constraint ck_is_json check (json_data is json);

Tabelle wurde geändert.
Von nun an nimmt die Tabelle nur noch JSON entgegen - andere Daten werden mit einer Fehlermeldung abgewiesen.

SQL-Funktionen: JSON_VALUE

Jetzt geht es daran, mit SQL Abfragen auf die JSON-Inhalte durchzuführen. Die erste Funktion ist JSON_VALUE - sie dient dazu, einzelne (skalare) Werte (und nur diese) aus dem JSON zu extrahieren. Kurz gesagt: JSON_VALUE kann verwendet werden, wenn genau ein Wert als Rückgabe erwartet wird.
select json_value(json_data, '$.person.firstname' ) 
from tab_json
where name = '1. JSON'
/

JSON_VALUE(JSON_DATA,'$.PERSON.FIRSTNAME')
--------------------------------------------
Carsten

1 Zeile wurde ausgewählt.
JSON_VALUE nimmt ein JSON-Dokument (oder eine Tabellenspalte mit JSON-Dokumenten) und einen JSON Pfadausdruck (JSON Path Expression) entgegen. Im Pfadausdruck repräsentiert das Dollarzeichen ($) das JSON-Dokument als ganzes. Per Punktnotation kann man nun durch die Hierarchie navigieren. $.person.firstname navigiert also zunächst ins Objekt person und dort zum Attribut firstname. Selektiert man dagegen nur den Knoten person, welcher ja ein (aus mehreren Attributen bestehendes) Objekt ist ...
select json_value(json_data, '$.person' ) 
from tab_json
where name = '1. JSON'
/

JSON_VALUE(JSON_DATA,'$.PERSON')
--------------------------------------------------------------------------------
- SQL NULL -

1 Zeile wurde ausgewählt.
... so erhält man gar nichts, obwohl der Knoten person sehr wohl vorhanden ist. Tatsächlich ist hier ein Fehler aufgetreten, allerdings hat die Datenbank keine Fehlermeldung geliefert. Die JSON-Funktionen können sich im Fehlerfall variabel verhalten - JSON_VALUE liefert im Fehlerfall standardmäßig SQL NULL zurück. Allerdings kann man dieses Verhalten mit der ON ERROR-Klausel ändern.
select json_value(json_data, '$.person' error on error) 
from tab_json
where name = '1. JSON'
/

FEHLER in Zeile 2:
ORA-40456: JSON_VALUE wurde als nicht-skalarer Wert ausgewertet
Mit ERROR ON ERROR wird festgelegt, dass die Datenbank im Fehlerfall auch wirklich eine Fehlermeldung auslösen soll. Die JSON-Funktionen arbeiten standardmäßig mit EMPTY ON ERROR, lösen also keine Fehlermeldung aus, so dass die Anwendung bei JSON-Dokumenten, die nicht zur Query passen, trotzdem weitermachen kann.

SQL-Funktionen: JSON_QUERY

JSON_QUERY wird ganz ähnlich wie JSON_VALUE verwendet, im Gegensatz dazu muss der Pfadausdruck eine gültige JSON-Struktur selektieren, also auf ein JSON-Objekt oder -Array zeigen. Ein skalarer Wert (ein Attributwert) ist hier nicht erlaubt. Den Unterschied erkennt man am besten, wenn man die beiden obigen Abfragen mit JSON_QUERY anstelle von JSON_VALUE ausführt. Damit wir Fehler besser erkennen können, geben wir auch gleich die Klausel ERROR ON ERROR an. Zuerst wird $.person selektiert.
select json_query(json_data, '$.person' PRETTY ERROR ON ERROR ) 
from tab_json
/

JSON_QUERY(JSON_DATA,'$.PERSON'PRETTYERRORONERROR)
----------------------------------------------------

  {
    "firstname" : "Carsten",
    "lastname" : "Czarski",
    "year" : 2014
  }


  [
    {
      "firstname" : "Carsten",
      "lastname" : "Czarski",
      "year" : 2014
    },
    {
      "firstname" : "John",
      "lastname" : "Doe",
      "year" : 2015
    }
  ]

2 Zeilen ausgewählt.
Wie man sieht, extrahiert JSON_QUERY das Objekt person problemlos und gibt es zurück. Im ersten JSON Dokument ist dies ein einzelnes Objekt, im zweiten ein Array mit zwei Elementen. Diese Flexibilität ist bei JSON durchaus normal. Das Schlüsselwort PRETTY sorgt dafür, dass das JSON lesbar formatiert zurückgegeben wird; in produktiven Anwendungen, in denen das JSON von anderen Programmen konsumiert wird, ist das normalerweise nicht nötig - im Entwicklungsprozess kann es aber durchaus hilfreich sein. Die zweite Abfrage, die direkt auf ein skalares Objektattribut abzielt, liefert mit JSON_QUERY ein anderes Ergebnis ...
select json_query(json_data, '$.person.firstname' PRETTY ERROR ON ERROR ) 
from tab_json
/

FEHLER in Zeile 2:
ORA-40480: Ergebnis kann nicht ohne Array-Wrapper zurückgegeben werden
Wie schon gesagt, muss der JSON-Pfadausdruck bei JSON_QUERY auf ein Objekt oder Array zeigen, nicht auf einen skalaren Wert. Man kann dem begegnen, indem die Klausel WITH WRAPPER mitgegeben wird. Das sähe dann so aus:
select json_query(json_data, '$.person.firstname' PRETTY WITH WRAPPER ERROR ON ERROR ) 
from tab_json
/

JSON_QUERY(JSON_DATA,'$.PERSON.FIRSTNAME'PRETTYWITHWRAPPERERRORONERROR)
-------------------------------------------------------------------------------
[
  "Carsten"
]

[
  "Carsten",
  "John"
]

2 Zeilen wurde ausgewählt.
Nun hat die Datenbank die Ergebnisse in eckige Klammern eingefasst - in JSON haben diese eine Bedeutung, denn sie legen fest, dass nun ein JSON-Array vorliegt. Wozu das gut ist? Dieses Ergebnis kann einem JSON-Parser übergeben und von diesem problemlos verarbeitet werden - das wäre mit dem einfachen String nicht machbar gewesen. Die Klausel WITH WRAPPER macht also aus dem Ergebnis von JSON_QUERY ein Array - das gilt auch, wenn JSON_QUERY ohnehin schon ein ganzes Objekt selektiert.
select json_query(json_data, '$.person' PRETTY WITH WRAPPER ERROR ON ERROR ) 
from tab_json
/

JSON_QUERY(JSON_DATA,'$.PERSON'PRETTYWIT
----------------------------------------
[
  {
    "firstname" : "Carsten",
    "lastname" : "Czarski",
    "year" : 2014
  }
]
:

2 Zeilen wurden ausgewählt.

SQL-Funktionen: JSON_TABLE

JSON_TABLE ist schließlich die Power-Funktion für JSON in der Datenbank, denn sie kann ein komplexes JSON-Objekt in eine flache Tabelle übersetzen - ganz ähnlich wie ihr Pendant XMLTABLE das für XML-Dokumente vermag.
select t.name json_name, j.fname, j.lname, j.year
from tab_json t, json_table (
  json_data,
  '$.person'
  columns (
    fname  varchar2(20) path '$.firstname',
    lname  varchar2(20) path '$.lastname',
    year   number       path '$.year'
  )
) j
/ 

JSON_NAME       FNAME                LNAME                      YEAR
--------------- -------------------- -------------------- ----------
1. JSON         Carsten              Czarski                    2014
3. wieder JSON  ?                    ?                    ?

2 Zeilen ausgewählt.
Der Pfadausdruck in JSON_TABLE selektiert ein JSON-Objekt oder -Array; in der COLUMNS-Klausel werden dessen Attribute dann auf Tabellenspalten der Ergebnismenge abgebildet. Obiges Beispiel selektiert den Knoten person, dessen Attribute firstname, lastname und year dann mit COLUMNS als Ergebisspalten deklariert werden. Für das erste JSON, in dem person ein Objekt mit den besagten drei Attributen ist, funktioniert das. Im zweiten JSON-Dokument ist das Objekt person aber ein Array - demnach enthalten die Elemente des Arrays die Attribute, nicht das Array selbst. Also9 bekommen wir für das zweite JSON-Dokument SQL NULL zurück. Die Elemente eines Arrays müssen im JSON Pfadausdruck mit [*] explizit angesprochen werden.
select t.name json_name, j.fname, j.lname, j.year
from tab_json t, json_table (
  json_data,
  '$.person[*]'
  columns (
    fname  varchar2(20) path '$.firstname',
    lname  varchar2(20) path '$.lastname',
    year   number       path '$.year'
  )
) j
/ 

JSON_NAME       FNAME                LNAME                      YEAR
--------------- -------------------- -------------------- ----------
3. wieder JSON  Carsten              Czarski                    2014
3. wieder JSON  John                 Doe                        2015

2 Zeilen ausgewählt.
Schauen wir uns das mit einem anderen JSON-Dokument an. Die Blogger-Plattform, auf der dieser Blog gehostet wird, stellt ebenfalls JSON-Feeds bereit - die letzten 25 Postings dieses Blogs können als JSON abgerufen werden.
Auf diesem JSON wollen wir nun mit JSON_TABLE arbeiten.
/*
 * Achtung: PL/SQL Netzwerk-ACL einrichten für Netzwerkzugriffe
 *          Bei Bedarf Proxy-Server setzen
 */

select 
  datum, 
  titel
from json_table (
  httpuritype('http://sql-plsql-de.blogspot.com/feeds/posts/default?alt=json').getblob() 
  FORMAT JSON,
  '$.feed.entry[*]' 
  columns (
    titel  varchar2(200) path '$."title"."\u0024t"',     -- \u0024 = "$"
    datum  varchar2(50)  path '$."published"."\u0024t"'  -- \u0024 = "$"
  )
)
/

2014-07-11T13:54:54.335+01:00
Monatliches Datenbank-Update für Entwickler

2014-06-04T08:00:12.155+01:00
Dateien per FTP in eine (eigene) Tabelle laden - Teil II

2014-05-15T17:24:04.254+01:00
XML DB Repository anders genutzt: Dateien per FTP in eine (eigene) Tabelle laden

2014-04-23T14:53:09.696+01:00
Tricks mit externen Tabellen: Unix "ps" per SELECT ausführen

2014-04-02T16:00:00.783+01:00
Veranstaltung "Unstrukturierte Daten in Oracle" im Mai 2014

:
Das JSON-Objekt entry ist ein Array - für jedes Posting enthält es einen Eintrag (ein Objekt) mit den Attributen dieses Postings. Also selektiert der JSON-Pathausdruck von JSON_TABLE $.entry. Die Attribute einer entry Instanz, die als Ergebnismenge zurückgeliefert werden sollen, werden in der COLUMNS-Klausel deklariert.
Das JSON muss gar nicht unbedingt in einer Tabelle liegen; es kann auch on-the-fly aus dem Internet geladen oder aus einer externen Tabelle (also dem Dateisystem) gelesen werden - die Möglichkeiten sind vielfältig. Als ersten Einblick in die JSON-Funktionen möchte ich es hierbei belassen - wie man JSON indiziert, soll einem eigenen Blog-Posting vorbehalten bleiben. Viel Spaß auf jeden Fall beim Ausprobieren. Die zur JSON-Unterstützung findet sich übrigens als Kapitel 39 des XML DB Developers' Guide.
The latest database patchset 12.1.0.2 is available. And like other patchsets in the past, this one is not a pure "patchset", it introduces new features as well.
  • Oracle In-Memory Database
  • Native JSON support
  • Approximate COUNT DISTINCT
  • :
  • :
In this blog posting, I'll focus on the native JSON support feature. I will not explain JSON itself, there are plenty of resources about that in the internet (e.g. Wikipedia). We'll start (as always) with a table to store JSON documents. In contradiction to XML, there is no new datatype for JSON. JSON can be stored as VARCHAR2, NVARCHAR2, BLOB or CLOB; the SQL functions will work with all of these. If you already have JSON stored in your database tables, no conversion or migration is required. And really all database clients will support JSON right from the beginning, because there is no new data type.
create table tab_json (
  id           number        generated always as identity,
  name         varchar2(200),
  json_data   clob
)
/ 
We can start inserting rows into that table immediately. The following two commands will insert a JSON instance and another one, which is no valid JSON. As we would habe expected: Both SQL INSERT statements succeed.
insert into tab_json (name, json_data) values (
  '1. JSON', 
  '{person: {firstname: "Carsten", lastname: "Czarski", year: 2014}}'
)
/

insert into tab_json (name, json_data) values (
  '2. no JSON, but XML', 
  '<person><firstname>Carsten</firstname><lastname>Czarski</lastname><year>2014</year></person>'
)
/

insert into tab_json (name, json_data) values (
  '3. JSON again',
  '{person: [{firstname: "Carsten", lastname: "Czarski", year: 2014}, {firstname: "John", lastname: "Doe", year: 2015}]}'
)
/

commit
/
Before we can start working with that data, we need to know, which row contains valid JSON and which does not. For this, Oracle introduces the SQL operators IS JSON and IS NOT JSON.
select name from tab_json where json_data is json
/

NAME
---------------------------------------------
1. JSON
3. JSON again

2 rows selected.

select name from tab_json where json_data is not json
/

NAME
--------------------------------------------
2. no JSON, but XML

1 row selected.
Of course, we can also create a check constraint using the IS JSON operator. This will make sure, that all rows contain valid JSON. First, we'll delete the "non-JSON" row and then we'll create the constraint ...
SQL> delete from tab_json where name = '2. no JSON, but XML';

1 row deleted.

SQL> alter table tab_json add constraint ck_is_json check (json_data is json);

Table altered.
From now on, the table column will accept only valid JSON instances. Otherwise, the check constraing will throw an error message.

SQL functions: JSON_VALUE

Now we'll start executing SQL queries based on the stored JSON data. The first SQL function is JSON_VALUE - it is for querying single (scalar) values. Use JSON_VALUE when you expect a singe scalar value as the result of your query. The following example illustrates this.
select json_value(json_data, '$.person.firstname' ) 
from tab_json
where name = '1. JSON'
/

JSON_VALUE(JSON_DATA,'$.PERSON.FIRSTNAME')
--------------------------------------------
Carsten

1 row selected.
The SQL function takes the JSON column and a JSON Path expression as arguments. Within the Path Expression, the dollar sign represents the JSON document. Using dot-notation, we can walk through the object hierarchy and select attributes. Thus, $.person.firstname navigates to the person object and then to the firstname attribute. If we selected the person node, which is an object and not a scalar value ...
select json_value(json_data, '$.person' ) 
from tab_json
where name = '1. JSON'
/

JSON_VALUE(JSON_DATA,'$.PERSON')
--------------------------------------------------------------------------------
- SQL NULL -

1 row selected.
Although the node $.person exists (it is there, it is an object), we get no result. Remember? JSON_VALUE is for retrieving scalar values only. But why did we not get an error message? Because the JSON functions are variable regarding their error handling. By default, JSON_VALUE returns SQL NULL in case of an error. If we want to have an error message, we need to specify that with the ON ERROR clause.
select json_value(json_data, '$.person' error on error) 
from tab_json
where name = '1. JSON'
/

ERROR at line 2:
ORA-40456: JSON_VALUE evaluated to non-scalar value
ERROR ON ERROR lets the database really throw error messages on case of errors. Alternatives are EMPTY ON ERROR and NULL ON ERROR. Whereas the former returns an empty JSON array, the latter returns SQL NULL. Both are useful when the application needs a valid JSON result in any case (because a JSON parser processes it). When, on the other hand, the state of the application would be unpredictable, you are better off with explicitly throwing an error message using ERROR ON ERROR.

SQL functions: JSON_QUERY

JSON_QUERY is used similar to JSON_VALUE, but in opposition, it is designed to select valid JSON objects only. So the JSON path expression, passed to JSON_QUERY, must target a JSON array or a JSON object. It must not match a scalar value. The difference becomes very clear, when we execute the previous two queries with JSON_QUERY instead of JSON_VALUE. To recognize errors immediately, we'll pass ERROR ON ERROR right from the beginning. First, a query selecting $.person.
select json_query(json_data, '$.person' PRETTY ERROR ON ERROR ) 
from tab_json
/

JSON_QUERY(JSON_DATA,'$.PERSON'PRETTYERRORONERROR)
----------------------------------------------------

  {
    "firstname" : "Carsten",
    "lastname" : "Czarski",
    "year" : 2014
  }


  [
    {
      "firstname" : "Carsten",
      "lastname" : "Czarski",
      "year" : 2014
    },
    {
      "firstname" : "John",
      "lastname" : "Doe",
      "year" : 2015
    }
  ]

2 rows selected.
While JSON_VALUE threw an error, JSON_QUERY executes successfully. The first row is a single JSON object, the second one is a JSON array containing two elements - this variety is usual in JSON environments. The keyword PRETTY lets the database use line breaks and indentation to produce a human-readable output. This is very useful during development, for production, when JSON is only consumed by other programs, it should be turned off. The other query, which selected the yfirstname attribute, returns a different result ...
select json_query(json_data, '$.person.firstname' PRETTY ERROR ON ERROR ) 
from tab_json
/

ERROR at line 1:
ORA-40480: result cannot be returned without array wrapper
As already stated, JSON_QUERY must select a JSON object or array - scalar values are not allowed. But the JSON_QUERY function allows us to circumvent this by using the WITH WRAPPER clause.
select json_query(json_data, '$.person.firstname' PRETTY WITH WRAPPER ERROR ON ERROR ) 
from tab_json
/

JSON_QUERY(JSON_DATA,'$.PERSON.FIRSTNAME'PRETTYWITHWRAPPERERRORONERROR)
-------------------------------------------------------------------------------
[
  "Carsten"
]

[
  "Carsten",
  "John"
]

2 rows selected.
Now, JSON_QUERY wrapped the results into a JSON array. Since an array is a valid JSON structure, no error is thrown. This also applies, when the path expression targets non-scalar values (objects or array) - these are wrapped into an array anyway.
select json_query(json_data, '$.person' PRETTY WITH WRAPPER ERROR ON ERROR ) 
from tab_json
/

JSON_QUERY(JSON_DATA,'$.PERSON'PRETTYWIT
----------------------------------------
[
  {
    "firstname" : "Carsten",
    "lastname" : "Czarski",
    "year" : 2014
  }
]
:

2 rows selected.

SQL functions: JSON_TABLE

JSON_TABLE is the most powerful JSON function. Like its pendant XMLTABLE, it is able to extract multiple values from the JSON, and to project these as the result set of the relational query.
select t.name json_name, j.fname, j.lname, j.year
from tab_json t, json_table (
  json_data,
  '$.person'
  columns (
    fname  varchar2(20) path '$.firstname',
    lname  varchar2(20) path '$.lastname',
    year   number       path '$.year'
  )
) j
/ 

JSON_NAME       FNAME                LNAME                      YEAR
--------------- -------------------- -------------------- ----------
1. JSON         Carsten              Czarski                    2014
3. JSON again   ?                    ?                    ?

2 rows selected.
The path expression passed to JSON_TABLE must select a JSON object or array. Within the COLUMNS clause, the attributes of the selected node are being projected as the SQL result set columns. The above example selects the person node. In the first JSON document, this node contains three attributes: firstname, lastname and year - the COLUMNS clause declares these as the result columns. But in the second JSON document, person is not an object, but an array. So the elements of the person array contain the attributes, not the person array itself. Therefore we get SQL NULL as result for the second JSON document. Array elements must be explicitly selected in the JSON path expression with [*].
select t.name json_name, j.fname, j.lname, j.year
from tab_json t, json_table (
  json_data,
  '$.person[*]'
  columns (
    fname  varchar2(20) path '$.firstname',
    lname  varchar2(20) path '$.lastname',
    year   number       path '$.year'
  )
) j
/ 

JSON_NAME       FNAME                LNAME                      YEAR
--------------- -------------------- -------------------- ----------
3. JSON again   Carsten              Czarski                    2014
3. JSON again   John                 Doe                        2015

2 rows selected.
Lets try JSON_TABLE with another example. The Blogger platform which hosts this blog, also offers a JSON feed. You can retrieve the last 25 postings in JSON format.
/*
 * Achtung: PL/SQL Netzwerk-ACL einrichten für Netzwerkzugriffe
 *          Bei Bedarf Proxy-Server setzen
 */

select 
  datum, 
  titel
from json_table (
  httpuritype('http://sql-plsql-de.blogspot.com/feeds/posts/default?alt=json').getblob() 
  FORMAT JSON,
  '$.feed.entry[*]' 
  columns (
    titel  varchar2(200) path '$."title"."\u0024t"',     -- \u0024 = "$"
    datum  varchar2(50)  path '$."published"."\u0024t"'  -- \u0024 = "$"
  )
)
/

2014-07-11T13:54:54.335+01:00
Monatliches Datenbank-Update für Entwickler

2014-06-04T08:00:12.155+01:00
Dateien per FTP in eine (eigene) Tabelle laden - Teil II

2014-05-15T17:24:04.254+01:00
XML DB Repository anders genutzt: Dateien per FTP in eine (eigene) Tabelle laden

2014-04-23T14:53:09.696+01:00
Tricks mit externen Tabellen: Unix "ps" per SELECT ausführen

2014-04-02T16:00:00.783+01:00
Veranstaltung "Unstrukturierte Daten in Oracle" im Mai 2014

:
The JSON path expression $.entry selects a JSON array - which contains one element for each blog posting. Each element is a JSON objects with attributes containing information about this very blog posting. The COLUMNS clause then projects these out as relational columns. As seen, JSON does not need to be stored within the database - we can also grab JSON instances from the internet or the file system and process these on-the-fly.
This concludes my first blog posting on JSON support in the Oracle database. More are to come. If you like, install your 12.1.0.2 database and try it out. The JSON documentation is part of the XML DB Developers' Guide - Chapter 39.

1 Kommentar:

chrisonoracle hat gesagt…

Hallo Carsten,

sehr interessant is auch die Pfad-Navigation:

APEX_050000@ora12g> create table json_test (i number, t varchar2(4000));

Table created.

APEX_050000@ora12g> insert into json_test values (1,
2 '{ "PONumber": 1600, "NESTED": [ { "k1": 1, "k2": false }, { "k1": 111 }]}');

1 row created.

APEX_050000@ora12g> select t.PONumber from json_test;
select t.PONumber from json_test
*
ERROR at line 1:
ORA-00904: "T"."PONUMBER": invalid identifier


APEX_050000@ora12g> alter table json_test add constraint json_test_ck_json check (t is json);

Table altered.

APEX_050000@ora12g> select j.t.PONumber from json_test j;

PONUMBER
--------
1600

1 row selected.

APEX_050000@ora12g> select j.t.NESTED.k1 from json_test j;

NESTED
-------
[1,111]

1 row selected.

Beliebte Postings