PUBLIC SAP HANA Platform 2.0 SPS 04 Document Version: 1.1 – 2019-10-31

SAP HANA JSON Document Store Guide company. All rights reserved. affiliate

THE BEST RUN 2019 SAP SE or an SAP © Content

1 SAP HANA JSON Document Store Guide...... 4

2 Introduction to SAP HANA JSON Document Store...... 5

3 Getting Started with the JSON Document Store...... 7

4 Collections...... 8

5 JSON Document Store Statements...... 9 5.1 Enable/Disable the JSON Document Store...... 9 Enable the SAP HANA JSON Document Store...... 9 Disable the SAP HANA JSON Document Store...... 10 5.2 Data Definition Statements...... 10 CREATE COLLECTION Statement...... 10 DROP COLLECTION Statement...... 11 TRUNCATE COLLECTION Statement...... 12 RENAME COLLECTION Statement...... 13 ALTER COLLECTION Statement (Checkpoints)...... 14 5.3 SELECT Statement...... 16 5.4 Data Manipulation Statements...... 21 INSERT Statement...... 21 UPDATE Statement...... 23 DELETE Statement...... 28 5.5 Data Types...... 30 5.6 Load/Unload a Collection...... 32 LOAD Statement...... 32 UNLOAD Statement...... 33 5.7 Native Aggregation...... 34

6 Import and Export...... 35

7 Data Type Handling and Schema-Flexibility...... 36 7.1 Data Types within the Document Store...... 36 7.2 Crossing Engine Boundaries...... 37

8 Changes from SPS 03 to SPS 04...... 38

9 Escape Sequences and Unicode in the SAP HANA Document Store...... 39 9.1 Background...... 39 9.2 Special Case "Forward Slash"...... 41

SAP HANA JSON Document Store Guide 2 PUBLIC Content 9.3 Special Case "Unicode"...... 42 9.4 Identifiers...... 43 9.5 Corrections...... 43

SAP HANA JSON Document Store Guide Content PUBLIC 3 1 SAP HANA JSON Document Store Guide

This guide explains the SAP HANA JSON Document Store.

The information in the guide is organized as follows:

● SAP HANA JSON Document Store Guide ● Introduction to SAP HANA JSON Document Store ● Getting Started with JSON Document Store ● Collections ● SQL Statements ● Import and Export ● Data Type Handling and Schema-Flexibility ● Changes from SPS 03 to SPS 04 ● Escape Sequences and Unicode in the SAP HANA Document Store

SAP HANA JSON Document Store Guide 4 PUBLIC SAP HANA JSON Document Store Guide 2 Introduction to SAP HANA JSON Document Store

The SAP HANA provides a Document Store for JSON documents. This is an independent store, in addition to the Column and Row Stores that are well-known in SAP HANA. The Document Store is available for the SAP HANA Express Edition.

Definition of SAP HANA JSON Document Store

Usually data is being stored in tables, with columns and rows, where for each column a strict definition or schema defines layout and data types. Moreover, tables are "flat" in the sense that they are not deeply nested or hierarchical. To represent a piece of information in the normalized representation, joins among multiple flat tables may be required.

 Note

The features "Flexible table" and "Multi-value attributes" break up these hard constraints.

The SAP HANA JSON Document Store follows the rules of JSON documents:

● Data may be deeply nested. ● There is no a priori definition of which fields exist or which data type they are associated with (schema- less). ● The stored data describes its own structure, which is being referred to as "semi-structured". ● Whereas in the Column and Row Store, data is stored in tables, JSON data is stored in so-called "collections".

Benefits of SAP HANA JSON Document Store

The SAP HANA Document Store is an ordinary SAP HANA service. This means that the JSON data is part of SAP HANA's backup & recovery, failover, system replication, point-in-time recovery etc. Also, a single transaction may span Row, Column and Document Store, commits are of course atomic. There is no asterisk after "ACID" that somehow limits any of the four properties.

With the Document Store – and it being a full member of the SAP HANA family – you can store your JSON data in it and use it across various SAP HANA engines, like hierarchies, graph and spatial. The full ACID properties allow you to use your JSON data without worrying about lesser consistency. With the built-in Document Store, there are no additional operational tasks that would be needed to maintain a dedicated, secondary database.

SAP HANA JSON Document Store Guide Introduction to SAP HANA JSON Document Store PUBLIC 5 Usage of the SAP HANA JSON Document Store

One of the main use cases for using the Document Store is of course if your application already uses JSON. If your data is JSON and you need to store it, for long-term processing or for intermediates, the Document Stores is beneficial. It allows you to work on JSON data using filters, offers native aggregation and allows using your JSON data in other SAP HANA engines. For example, you may join your JSON data with Column Store tables.

More than that, the Document Store may be beneficial for you in the following ways:

● Have a data model that requires many tables and joins are costly (de-normalization, using schema- flexibility) ● Have the need for many or changing attributes, like attributes for a "Product" object ("lumen", "mileage", etc.) that cannot be defined upfront ● Need a means for extensibility (using schema-flexibility)

Diagnostics

You can use database diagnostics (tracing) to analyze the details of Document Store operations. All Document Store trace components are identifiable by the "docstore*" prefix.

Traces which are explicitly designed to trace SQL strings and intermediate results have the suffix "*_data". These traces may contain sensitive data therefore set the trace level of these data tracers only to DEBUG, INFO or WARNING if tracing sensitive information is acceptable. The trace levels ERROR and FATAL will not print any extra sensitive information and are safe to use in this respect. For more information, see Configure Traces in the SAP HANA Administration Guide.

The Term "Document Store"

The term "Document Store" was defined by the NoSQL community - as JSON "artifacts" are named "documents". Do not confuse "documents" with text or PDF files - the JSON Document Store cannot handle them.

In technical terms, e.g. in process names, the Document Store is sometimes referred to as "DocStore". This is a synonym.

Related Information

SAP HANA Administration Guide

SAP HANA JSON Document Store Guide 6 PUBLIC Introduction to SAP HANA JSON Document Store 3 Getting Started with the JSON Document Store

To access the SQL features of JSON Document Store, you must first enable the feature on the System DB for a tenant (for example ALTER DATABASE XYZ123 ADD 'docstore'). For more information, see Enable the SAP HANA JSON Document Store [page 9] and Disable the SAP HANA JSON Document Store [page 10].

The following example shows how the Document Store may be used:

CREATE COLLECTION Customers;

INSERT INTO Customers VALUES({"name": 'Paul', "address": { "street": 'Hauptstraße 10', "city": 'Heidelberg' } }); SELECT * FROM Customers WHERE "address"."city" = 'Heidelberg'

SELECT "address"."city", COUNT(*) FROM Customers GROUP BY "address"."city";

In the INSERT statement you can see the newly introduced "Object Expression" that allows the formation of JSON objects directly in SQL. But please note that this really is SQL and not JSON. It follows the SAP HANA SQL rules for identifiers and string literals: identifiers are in double-quotes, whereas string literals are in single- quotes. There is also a string interface available if you have a JSON-formatted string at hand.

In the same example, you can see a SELECT using a path expression ("address"."city") to filter for the documents of interest.

The last SELECT statement shows a native aggregation that is directly being performed within the Document Store.

It is also possible to join with Column Store table, with explicit or implicit views:

CREATE COLUMN TABLE SomeColumnStoreTable ("name" NVARCHAR(20), "age" INT);

INSERT INTO SomeColumnStoreTable VALUES('Paul', 34); WITH myView AS (SELECT "name", "address"."city" AS "city" FROM Customers)

SELECT cst."name", cst."age", myView."city" FROM myView INNER JOIN SomeColumnStoreTable AS cst ON myView."name" = cst."name";

This join is being reused in section Crossing Engine Boundaries [page 37].

Related Information

Enable the SAP HANA JSON Document Store [page 9] Disable the SAP HANA JSON Document Store [page 10] Crossing Engine Boundaries [page 37]

SAP HANA JSON Document Store Guide Getting Started with the JSON Document Store PUBLIC 7 4 Collections

The "Collection" artifacts are like tables. In fact, they are a subtype. Hence, all monitoring or system views for tables also show collections. The following query can be used to differentiate and to list all collections in the system:

SELECT * FROM TABLES WHERE TABLE_TYPE = 'COLLECTION';

For HDI, a dedicated artifact exists – hdbcollection – to create and populate collections. The usage hdbcollection of course, requires the Document Store to be started upfront. Otherwise the attempted use of hdbcollection will result in an error. For more information, see Document Store Collections (.hdbcollection) in the SAP HDI Artifact Types and Build Plug-ins Reference.

Limits

There is no limit for the number of documents in a collection.

Although, a document must not exceed 8 MB in size.

SQL Parameters

The Document Store does not support SQL parameters. This may affect the application's ability to prevent SQL injection.

SAP HANA JSON Document Store Guide 8 PUBLIC Collections 5 JSON Document Store Statements

The statements described in this section enable you to use the SAP HANA database as a JSON document store.

5.1 Enable/Disable the JSON Document Store

The Document Store is a dedicated service. It has to be enabled and disabled explicitly by the administrator on the System DB for a tenant.

5.1.1 Enable the SAP HANA JSON Document Store

The Document Store is a dedicated service. It has to be enabled explicitly by the administrator on the System DB for a tenant to use.

To enable the JSON Document store for a tenant, you need to execute the following statement on the System DB:

ALTER DATABASE ADD 'docstore';

 Note

If the JSON Document Store is enabled for a tenant, the service docstore is running for the tenant.

 Note

A tenant cannot have more than one Document Store process.

The following statement enables the JSON Document Store for the tenant XYZ123:

ALTER DATABASE XYZ123 ADD 'docstore';

SAP HANA JSON Document Store Guide JSON Document Store Statements PUBLIC 9 5.1.2 Disable the SAP HANA JSON Document Store

The Document Store is a dedicated service. It has to be disabled explicitly by the administrator on the System DB for each tenant individually.

To disable the JSON Document store for a tenant, you need to execute the following statement on the System DB:

ALTER DATABASE REMOVE 'docstore' AT ':';

The following statement disables the JSON Document Store for the tenant XYZ123 on myHost:

ALTER DATABASE XYZ123 REMOVE 'docstore' AT 'myHost:30040';

 Note

Be aware that you can only remove the Document Store process if it does not hold any data. This means that all collections have to be dropped beforehand.

5.2 Data Definition Statements

Data definition statements define structures in the SAP HANA database.

5.2.1 CREATE COLLECTION Statement

Creates a collection table for storing JSON documents.

Syntax

CREATE COLLECTION [TABLE]

Syntax Elements

Specifies a unique identifier for the collection table.

::= [[.].]

SAP HANA JSON Document Store Guide 10 PUBLIC JSON Document Store Statements Description

Use the CREATE COLLECTION statement to create collection tables for storing JSON documents. Collection tables behave similarly to tables in the SAP HANA database, and are treated as tables as well. The TABLE keyword in the syntax is optional.

The views TABLES and M_TABLES contain information about collections. The column TABLE_TYPE indicates, if a table is a collection table.

Examples

The following statements create a collection table called Customers, add a JSON document (row) to it, and then query the data.

CREATE COLLECTION Customers;

INSERT INTO Customers VALUES('{"name": "Paul", "address": {"street":"Hauptstraße 10","city":"Heidelberg"}}');

SELECT * FROM Customers WHERE "address"."city" = 'Heidelberg';

CUSTOMERS

{"name": "Paul", "address": {"street": "Hauptstraße 10", "city": "Heidelberg"}}

5.2.2 DROP COLLECTION Statement

Drops a collection table.

Syntax

DROP COLLECTION [ TABLE ]

Syntax Elements

Specifies the name of the collection table to drop.

::= [[.].]

SAP HANA JSON Document Store Guide JSON Document Store Statements PUBLIC 11 Specifies the drop option to use.

::= CASCADE | RESTRICT

CASCADE drops the collection table and any dependent objects. RESTRICT drops the collection table only when dependent objects do not exist. If RESTRICT is specified and a dependent object exists, then an error is returned.

If is not specified, then a non-cascaded drop is performed, which only drops the specified collection table. Dependent objects of the collection table are invalidated but not dropped.

Description

Drops a collection table from the database. When you drop a collection table, all JSON documents stored in the collection table are removed as well.

DROP COLLECTION fails if is a regular table, not a collection table.

Examples

The following statement drops a collection table called MyCollection.

DROP COLLECTION MyCollection;

The following statement drops a collection table called MyCollection2 and any associated views.

DROP COLLECTION MyCollection CASCADE;

5.2.3 TRUNCATE COLLECTION Statement

Deletes all JSON documents (entries) from a collection table.

Syntax

TRUNCATE COLLECTION [ TABLE ]

SAP HANA JSON Document Store Guide 12 PUBLIC JSON Document Store Statements Syntax Elements

Specifies the name of the collection table to truncate.

::= [[.].]

Description

Truncates all data from a table collection.

Examples

The following statement truncates a collection table called MyCollection.

CREATE COLLECTION myCollection;

INSERT INTO myCollection VALUES ('{ "firstname":"John", "lastname":"Smith", "age":45, "city":"New York" }'); INSERT INTO myCollection VALUES ('{ "firstname":"Amy", "lastname":"Jones", "age": 31, "city":"Los Angeles" }');

TRUNCATE COLLECTION MyCollection;

The following SQL statement returns an empty output:

SELECT * FROM MyCollection;

MYCOLLECTION

5.2.4 RENAME COLLECTION Statement

Renames a collection table.

Syntax

RENAME COLLECTION [ TABLE ] TO

SAP HANA JSON Document Store Guide JSON Document Store Statements PUBLIC 13 Syntax Elements

Specifies the collection table to rename.

::= [[.].]

Specifies a new name for the collection table.

::= [[.].]

Description

Renames a collection table.

Examples

The following statement renames a collection table called CollectionA to CollectionB.

RENAME COLLECTION CollectionA TO CollectionB;

5.2.5 ALTER COLLECTION Statement (Checkpoints)

Alters a collection table.

Syntax

ALTER COLLECTION [TABLE] CHECKPOINT [ FULL ]

Syntax Elements

SAP HANA JSON Document Store Guide 14 PUBLIC JSON Document Store Statements Specifies the identifier for the collection table you are altering.

::= [[.].]

CHECKPOINT [ FULL ]

CHECKPOINT FULL consolidates all logs, including waiting to acquire locks, if necessary. CHECKPOINT (without FULL) consolidates only log for data that is loaded into memory and for which no other parallel processing is taking place.

Description

When a JSON document store checkpoint is created, the virtual log file is truncated and a consolidated version is stored on disk.

When inserting, updating, or deleting documents, a log file is written. Over time the log grows and is likely to contain entries that are not required anymore (since, for example, a document may have been inserted first and deleted again some time afterwards, rendering the two log entries superfluous). Checkpoints are a consolidated version of data. Hence, you should trigger checkpoints from time to time. This will speed up loading of the data, i.e. after a process restart of crash, or after an UNLOAD of the collection.

Triggering a checkpoint is a manual administrative step.

When triggering a checkpoint on a collection, not all data may be checkpointed. This is even true when specifying the FULL keyword. Checkpointing may be skipped for parts of the data. This is due to asynchronous processes in the engine that shall not be blocked by the process. Also checkpointing depends on the transactional state of the data in your collections. When triggering a checkpoint, all the data that is not locked by asynchronous processes that is committed and garbage-collected, will be written. The rest is not. In a system that is under use, it is typical that not all data is being checkpointed. This is considered okay.

Examples

The following statement performs a full checkpoint on the collection myCollection:

ALTER COLLECTION myCollection CHECKPOINT FULL;

SAP HANA JSON Document Store Guide JSON Document Store Statements PUBLIC 15 5.3 SELECT Statement

Use this syntax to query data stored in collection tables.

Syntax

SELECT [ TOP ]

{

{ FROM

| [ DISTINCT ] [,...] } FROM

| <*> FROM [ [ AS ] ]

| FROM [ AS ]

}

[ WHERE ]

[ GROUP BY [,...] ]

[ ORDER BY [ ASC | DESC ] [,...] ]

[ LIMIT [ OFFSET ] ]

Syntax Elements

Specifies the name of the collection table to select from.

::= [[.].]

Specifies the path to a field in a JSON document (for example, "address"."street").

::=

::= [.[...]]

Specifies values to filter on.

::=

[ { AND | OR } [...]]

::= {

{ > | >= | < | <= | <> | = }

| BETWEEN AND

| IS NULL | IS { SET | UNSET }

}

IS SET | UNSET tests for values that have been set or unset for the specified key; for example, SELECT * FROM COL100 WHERE "k1"."k2" IS UNSET;.

SAP HANA JSON Document Store Guide 16 PUBLIC JSON Document Store Statements IS NULL tests for whether the value for a key is NULL. If a field is not set, it is also treated as being NULL; therefore a check for IS NULL returns true on non-existing fields. GROUP BY

Specifies a field to group the results by. ORDER BY

Specifies a field to order the results by. Sorting may yield unexpected results if any of the selected documents are missing , and/or have mixed data types in .

Sorting is straight forward with ORDER BY. But there are things to be aware of. First of all, it is discouraged to mix data types. But if you do, special semantics apply when using ORDER BY. The following example shows ORDER BY with mixed data types:

CREATE COLLECTION SortOrder;

INSERT INTO SortOrder VALUES({ "key": 1 }); INSERT INTO SortOrder VALUES({ "key": '2' }); INSERT INTO SortOrder VALUES({ "key": 3 }); INSERT INTO SortOrder VALUES({ "key": '4' });

SELECT * FROM SortOrder ORDER BY "key" ASC;

This returns the documents with the integers first, then the documents with the strings as per our own definition. Using different data types is discouraged. Hence, this should not be a typical use case. But if you do have different data types, be aware that the data will be ordered within each data type and also among data types given the precedence of data types. Use casting to enforce a data type and its ordering rules.

Moreover, if you order by a key that is not present in all documents, or not present at all, sorting will be partial. LIMIT

Returns the first records after skipping OFFSET .

Description

Use this syntax to query data stored in collection tables.

The following aggregate functions are supported when selecting from collection tables: COUNT(*), COUNT(), MIN() and MAX().

There are several ways to select from a collection:

● Select the entire document as a string:

SELECT * FROM Customers;

● Select individual fields from a collection (projection):

SELECT "name", "address"."city" FROM Customers;

SAP HANA JSON Document Store Guide JSON Document Store Statements PUBLIC 17 ● Construct a new JSON document with the Object Expression:

SELECT { "firstName": "name", "homeCity": "address"."city" } FROM Customers;

● Select with filter:

SELECT * FROM Customers WHERE "name" = 'Paul'; -- pay attention to double and single quotes!

● Select using the path expression:

SELECT * FROM Customers WHERE "address"."city" = 'Heidelberg';

● Select filtering by objects:

INSERT INTO Customers VALUES({ "name": { "firstName": 'Maria', "lastName": 'Smith' } });

SELECT * FROM Customers WHERE "name" = { "firstName": 'Maria', "lastName": 'Smith' };

Examples

1. The following statements create a collection table and insert JSON documents into it for use with the following examples:

CREATE COLLECTION OverSeasContacts;

INSERT INTO OverSeasContacts VALUES ('{ "firstname":"John", "lastname":"Smith", "age":45, "address": { "street": "Dietmar-Hopp-Allee", "city": "Heidelberg" } }'); INSERT INTO OverSeasContacts VALUES ('{ "firstname":"Amy", "lastname":"Jones", "age":31, "address": { "city": "Walldorf" } }'); INSERT INTO OverSeasContacts VALUES ('{ "firstname":"Elizabeth", "lastname":"Peterson", "age":19, "address": { "street": "Dietmar-Hopp-Allee", "city": "Heidelberg" } }'); INSERT INTO OverSeasContacts VALUES ('{ "firstname":"Carl", "lastname":"Patel", "age":21, "address": { "street": "", "city": "Walldorf" } }'); INSERT INTO OverSeasContacts VALUES ('{ "firstname":"Roger", "lastname":"Schroeder", "age":77, "address": { "street": "Dietmar-Hopp- Allee", "city": "Heidelberg" } }');

The following statement returns the contacts living in Heidelberg:

SELECT * FROM OverSeasContacts WHERE "address"."city" = 'Heidelberg';

OVERSEASCONTACTS

{"firstname": "John", "lastname": "Smith", "age": 45, "address": {"street": "Dietmar-Hopp-Allee", "city": "Heidelberg"}}

{"firstname": "Elizabeth", "lastname": "Peterson", "age": 19, "address": {"street": "Dietmar-Hopp-Allee", "city": "Heidelberg"}}

{"firstname": "Roger", "lastname": "Schroeder", "age": 77, "address": {"street": "Dietmar-Hopp-Allee", "city": "Heidelberg"}}

SAP HANA JSON Document Store Guide 18 PUBLIC JSON Document Store Statements The following statement returns the last name and age of contacts who are older than 40:

SELECT "lastname", "age" FROM OverSeasContacts WHERE "age" > 40 ORDER BY "lastname";

lastname age

Schroeder 77

Smith 45

The following statement returns the street names of contacts living in Heidelberg:

SELECT "address"."street" FROM OverSeasContacts WHERE "address"."city" = 'Heidelberg';

OVERSEASCONTACTS

Dietmar-Hopp-Allee

Dietmar-Hopp-Allee

Dietmar-Hopp-Allee

The following statement tests for documents where the value for "address"."street" is NULL:

SELECT * FROM OverseasContacts WHERE "address"."street" IS NULL;

OVERSEASCONTACTS

{"firstname": "Amy", "lastname": "Jones", "age": 31, "address": {"city": "Walldorf"}}

To join a collection table to a SAP HANA table, you can populate a view with the projected data from the collection and then join the view to the table data. To show how you can do this, the following statement creates a collection, populates it with data, and then creates a table to join the data with:

CREATE COLLECTION OverSeasContacts;

INSERT INTO OverSeasContacts VALUES ('{ "firstname":"John", "lastname":"Smith", "age":45, "address": { "street":"Dietmar-Hopp-Allee", "city":"Heidelberg" } }'); INSERT INTO OverSeasContacts VALUES ('{ "firstname":"Amy", "lastname":"Jones", "age":31, "address": { "street":"Werdung", "city":"Walldorf" } }'); INSERT INTO OverSeasContacts VALUES ('{ "firstname":"Carl", "lastname":"Patel", "age":21, "address": { "street":"Werdung", "city":"Walldorf" } }'); CREATE ROW TABLE ContactPurchases ( CustID NVARCHAR(10) UNIQUE NOT NULL, LastName NVARCHAR(50), ItemsPurchased NVARCHAR(50)); INSERT INTO ContactPurchases VALUES ( 2938742937, 'Smith', 'ball cap'); INSERT INTO ContactPurchases VALUES ( 5098043756, 'Smith', 'jersey'); INSERT INTO ContactPurchases VALUES ( 9298357700, 'Jones', 'keychain');

INSERT INTO ContactPurchases VALUES ( 2238759877, 'Patel', 'pen');

SAP HANA JSON Document Store Guide JSON Document Store Statements PUBLIC 19 The simplest way to join the collection and table data is to use an implicit view on the collection and join it with the table data:

WITH myViewForJoining AS (SELECT "lastname", "address"."city" FROM OverSeasContacts)

SELECT LastName, CustID, ItemsPurchased FROM ContactPurchases INNER JOIN myViewForJoining ON ContactPurchases.lastname = myViewForJoining."lastname";

You can also create a view on the collection and then select from that view, joining the table:

CREATE VIEW myViewForJoining AS (SELECT "lastname", "address"."city" FROM OverSeasContacts);

SELECT LastName, CustID, ItemsPurchased from ContactPurchases INNER JOIN myViewForJoining ON ContactPurchases.lastname = myViewForJoining."lastname";

LASTNAME CUSTID ITEMSPURCHASED

Smith 2938742937 ball cap

Smith 5098043756 jersey

Jones 9298357700 keychain

Patel 2238759877 pen

2. The following statements demonstrate the use of JSON object expressions when working with collection tables. The following statement creates a collection called TESTCOLLECTION and inserts JSON documents into it.

CREATE COLLECTION TESTCOLLECTION;

INSERT INTO TESTCOLLECTION VALUES( {"k1" : { "k2" : 30 } } ); INSERT INTO TESTCOLLECTION VALUES( {"k1" : { "k2" : 40 } } );

INSERT INTO TESTCOLLECTION VALUES( {"k1" : { "k2" : 'abc' } } );

Running a SELECT * statement on TESTCOLLECTION returns the following:

{"k1": {"k2": 30}}

{"k1": {"k2": 40}}

{"k1": {"k2": "abc"}}

Execute the following update, which uses JSON object expressions:

UPDATE TESTCOLLECTION SET "k1"."k2" = { "k3" : 'abc' } WHERE "k1"."k2" = 'abc';

Running a SELECT * statement on TESTCOLLECTION now returns the following:

{"k1": {"k2": 30}}

{"k1": {"k2": 40}}

{"k1": {"k2": {"k3": "abc"}}}

SAP HANA JSON Document Store Guide 20 PUBLIC JSON Document Store Statements Run the following SELECT statement:

SELECT { "a1" : 10 }, { "a2" : "k1" }

FROM TESTCOLLECTION WHERE "k1" = { "k2" : 30 };

The statement returns the result: {"a1": 10};{"a2": {"k2": 30}} Run the following SELECT statement:

SELECT * FROM TESTCOLLECTION

ORDER BY { "a1" : "k1"."k2" };

The statement returns the result:

{"k1": {"k2": 30}}

{"k1": {"k2": 40}}

{"k1": {"k2": {"k3": "abc"}}}

Run the following SELECT statement:

SELECT * FROM TESTCOLLECTION

ORDER BY { "a1" : "k1"."k2" } DESC;

The statement returns the result:

{"k1": {"k2": {"k3": "abc"}}}

{"k1": {"k2": 40}}

{"k1": {"k2": 30}}

5.4 Data Manipulation Statements

The following statements enable you to manipulate data in collection tables within the SAP HANA database.

5.4.1 INSERT Statement

Inserts JSON documents into a collection table.

Syntax

INSERT INTO VALUES ( )

SAP HANA JSON Document Store Guide JSON Document Store Statements PUBLIC 21 Syntax Elements

Specifies the collection table to insert JSON documents into it.

::= [[.].]

Specifies the JSON documents to insert.

::=

must be a single string representing a valid JSON document.

Description

Use this statement to insert JSON documents into a collection table. In collection tables, one row is a single JSON document.

There are two options to insert data. Either you insert a document as a string, or you use the Object Expression. When using the string, the string must be valid JSON. This in particular requires keys to be written in double- quotes and also string values require double-quotes. With the Object Expression, we want to make JSON a first class citizen in SQL. Its semantics follow the SQL rules for identifiers and string literals. It requires keys to be written in double-quotes or without any quotes like all identifiers, and string values in single-quotes. (If identifiers are written without double-quotes, they are automatically made upper-case.) This way it is consistent with WHERE clauses, and the like, as you will see in the subsequent chapters.

You have several options to insert data:

● Here is an example with JSON as a string:

INSERT INTO myCollection VALUES ('{ "myKey": "myValue" }');

● Here is the same example with the Object Expression:

INSERT INTO myCollection VALUES ({ "myKey": 'myValue' });

● SAP HANA offers bulk inserts for JSON data. Use the following statement to enter an array of documents:

INSERT INTO myCollection VALUES (?);

 Note

It is not possible to insert multiple JSON documents by means of INSERT other than this bulk interface.

SAP HANA JSON Document Store Guide 22 PUBLIC JSON Document Store Statements Examples

The following statements create a collection table and insert five JSON documents into it:

CREATE COLLECTION myCollection;

INSERT INTO myCollection VALUES ('{ "firstname":"John", "lastname":"Smith", "age":45, "city":"New York" }'); INSERT INTO myCollection VALUES ('{ "firstname":"Amy", "lastname":"Jones", "age": 31, "city":"Los Angeles" }'); INSERT INTO myCollection VALUES ('{ "firstname":"Elizabeth", "lastname":"Peterson", "age":19, "city":"Dublin" }'); INSERT INTO myCollection VALUES ('{ "firstname":"Carl", "lastname":"Patel", "age":21, "city":"Washington" }');

INSERT INTO myCollection VALUES ('{ "firstname":"Roger", "lastname":"Schroeder", "age":77, "city":"Boston" }');

The following statements use a subquery to insert values from one collection table into another:

CREATE COLLECTION myCollection1;

INSERT INTO myCollection1 VALUES ('{ "firstname":"John", "lastname":"Smith", "age":45, "city":"New York" }'); INSERT INTO myCollection1 VALUES ('{ "firstname":"Elizabeth", "lastname":"Peterson", "age":19, "city":"Dublin" }'); CREATE COLLECTION myCollection2; INSERT INTO myCollection2 ( SELECT * FROM myCollection1 WHERE "age">21 ) ;

SELECT * FROM myCollection2;

MYCOLLECTION2

{"firstname": "John", "lastname": "Smith", "age": 45, "city": "New York"}

The following statements create a collection table and insert JSON documents into it by using JSON object expressions:

CREATE COLLECTION TESTCOLLECTION;

INSERT INTO TESTCOLLECTION VALUES( {"k1" : { "k2" : 30 } } ); INSERT INTO TESTCOLLECTION VALUES( {"k1" : { "k2" : 40 } } );

INSERT INTO TESTCOLLECTION VALUES( {"k1" : { "k2" : 'abc' } } );

5.4.2 UPDATE Statement

Updates JSON documents in a collection table.

Syntax

UPDATE

[ | ]

[ WHERE ]

SAP HANA JSON Document Store Guide JSON Document Store Statements PUBLIC 23 Syntax Elements

Specifies the name of the collection table to update.

::= [[.].]

Sets or unsets fields and arrays. A field must not be specified more than once in the same statement - especially not as part of the SET and the UNSET clause at the same time.

::= { [ ] | [ ] }

::= SET = [, = [,...]]

::= UNSET [, [,...]]

::= { | }

Specifies a field where the value has to be updated. If exists, then the value is overwritten with the new value. A field must not be specified more than once in the same statement.

Specifies the position of a value to update in the array (for example, myArray[3] is position 3 of the array myArray).

Specifies the value to set to.

Specifies a new name for a field.

::= RENAME TO [, TO [, ...]]

If does not exist, then the document remains unchanged. If already exists, then an error is returned. If is used, cannot be used.

Specifies values to use to filter the results. If no WHERE clause is specified, then all documents in the collection table are updated.

::=

[ { AND | OR } [...]]

::= {

{ > | >= | < | <= | <> | = }

| BETWEEN AND

| IS NULL | IS { SET | UNSET } }

::=

::= [.[...]]

SAP HANA JSON Document Store Guide 24 PUBLIC JSON Document Store Statements IS SET | UNSET tests for values that have not been set for the specified key; for example, { "firstname":"", "lastname":"Smith"}.

IS NULL tests for NULL values in the specified key.

specifies a path to a field in a JSON document (for example, "address"."street").

Description

Use the UPDATE COLLECTION statement to set and unset fields, change field values, rename fields in JSON documents, and to replace entire documents

When using , if any identifier in does not exist, then the update operation creates it and sets it as specified.

Update Documents

You can update individual fields and there is no need to replace entire documents:

UPDATE SET = , ... [WHERE ];

Also, you can remove / "unset" existing fields using UNSET:

UPDATE UNSET , ... [WHERE ];

In each of the statements, you may specify multiple SET and UNSET clauses. You can also specify SET and UNSET in a single UPDATE statement.

Example:

CREATE COLLECTION myCollection;

INSERT INTO myCollection VALUES ({ "name": 'John' }); UPDATE myCollection SET "address" = {"street": 'First Street' }; SELECT * FROM myCollection; -- shows that all documents now have "address" set UPDATE myCollection SET "address"."street" = 'Second Street' WHERE "name" = 'John'; SELECT * FROM myCollection; UPDATE myCollection UNSET "address";

UPDATE myCollection SET "age" = 20, "rating" = 'A', UNSET "address";

Replace Documents

You can also replace entire documents with a single statement:

UPDATE SET = {"key": 'value', "newkey": 'newvalue', ...} WHERE "key" = 'value';

Example:

CREATE COLLECTION myCollection;

INSERT INTO myCollection VALUES ({ "name": 'John' }); INSERT INTO myCollection VALUES ({ "name": 'Sarah' }); UPDATE myCollection SET myCollection = ({ "firstName": 'Jonny', "lastName": 'Smith' }) WHERE "name" = 'John';

SAP HANA JSON Document Store Guide JSON Document Store Statements PUBLIC 25 Examples

1. The following statements create a collection table and insert JSON documents into it for use with the remaining examples in this topic.

CREATE COLLECTION OverSeasContacts;

INSERT INTO OverSeasContacts VALUES ('{ "firstname":"John", "lastname":"Smith", "age":45, "address": { "street": "Dietmar-Hopp-Allee", "city": "Heidelberg" } }'); INSERT INTO OverSeasContacts VALUES ('{ "firstname":"Amy", "lastname":"Jones", "age":31, "address": { "city": "Walldorf" } }'); INSERT INTO OverSeasContacts VALUES ('{ "firstname":"Elizabeth", "lastname":"Peterson", "age":19, "address": { "street": "Dietmar-Hopp-Allee", "city": "Heidelberg" } }'); INSERT INTO OverSeasContacts VALUES ('{ "firstname":"Carl", "lastname":"Patel", "age":21, "address": { "street": "", "city": "Walldorf" } }'); INSERT INTO OverSeasContacts VALUES ('{ "firstname":"Roger", "lastname":"Schroeder", "age":77, "address": { "street": "Dietmar-Hopp- Allee", "city": "Heidelberg" } }');

The following example updates "address"."street" to "Hauptstraße" for rows where "address"."city" is set to "Walldorf":

UPDATE OverSeasContacts SET "address"."street" = 'Hauptstraße' WHERE "address"."city" = 'Walldorf';

SELECT * FROM OverSeasContacts WHERE "address"."city" = 'Walldorf';

OVERSEASCONTACTS

{"firstname": "Amy", "lastname": "Jones", "age": 31, "address": {"city": "Walldorf", "street": "Hauptstraße"}}

{"firstname": "Carl", "lastname": "Patel", "age": 21, "address": {"street": "Hauptstraße", "city": "Walldorf"}}

The following example unsets "address"."street" for rows where "address"."city" is "Heidelberg":

UPDATE OverSeasContacts UNSET "address"."street" WHERE "address"."city" = 'Heidelberg';

SELECT * FROM OverSeasContacts WHERE "address"."city" = 'Heidelberg';

OVERSEASCONTACTS

{"firstname": "John", "lastname": "Smith", "age": 45, "address": {"city": "Heidelberg"}}

{"firstname": "Elizabeth", "lastname": "Peterson", "age": 19, "address": {"city": "Heidelberg"}}

{"firstname": "Roger", "lastname": "Schroeder", "age": 77, "address": {"city": "Heidelberg"}}

The following example changes the "street" key to "street name":

UPDATE OverSeasContacts RENAME "address"."street" TO "address"."street name";

SELECT * FROM OverSeasContacts;

SAP HANA JSON Document Store Guide 26 PUBLIC JSON Document Store Statements OVERSEASCONTACTS

{"firstname": "John", "lastname": "Smith", "age": 45, "address": {"city": "Heidelberg"}}

{"firstname": "Amy", "lastname": "Jones", "age": 31, "address": {"city": "Walldorf", "street name": "Hauptstraße"}}

{"firstname": "Elizabeth", "lastname": "Peterson", "age": 19, "address": {"city": "Heidelberg"}}

{"firstname": "Carl", "lastname": "Patel", "age": 21, "address": {"street name": "Hauptstraße", "city": "Walldorf"}}

{"firstname": "Roger", "lastname": "Schroeder", "age": 77, "address": {"city": "Heidelberg"}}

The following example sets a value for ARR[2] (position 2 in array ARR) for JSON documents where "age" is greater than 30:

CREATE COLLECTION myCollection1;

INSERT INTO myCollection1 VALUES ('{ "age":22, "ARR": ["a", "b", "", "d"] }'); INSERT INTO myCollection1 VALUES ('{ "age":44, "ARR": ["a", "b", "c", "d"] }'); UPDATE myCollection1 SET "ARR"[2] = 'newValue' WHERE "age">30;

SELECT * FROM myCollection1;

MYCOLLECTION1

{"age": 22, "ARR": ["a", "b", "c", "d"]}

{"age": 44, "ARR": ["a", "newValue", "c", "d"]}

The following example shows how to unset a field in an array:

CREATE COLLECTION myCollection1;

INSERT INTO myCollection1 VALUES ('{ "age":22, "ARR": ["a", "b", "c", "d"] }'); INSERT INTO myCollection1 VALUES ('{ "age":44, "ARR": ["a", "b", "c", "d"] }'); UPDATE myCollection1 UNSET "ARR"[2] WHERE "age">30;

SELECT * FROM myCollection1;

MYCOLLECTION1

{ "age":22, "ARR": ["a", "b", "c", "d"] }

{ "age":44, "ARR": ["a", "c", "d"] }

Example for : The following example shows how to rename a field:

CREATE COLLECTION myCollection1;

INSERT INTO myCollection1 VALUES ('{ "firstname":"John", "lastname":"Smith", "age":45, "address": { "street": "Dietmar-Hopp-Allee", "city": "Heidelberg" } }'); INSERT INTO myCollection1 VALUES ('{ "firstname":"Amy", "lastname":"Jones", "age":31, "address": { "street": "Hauptstraße", "city": "Walldorf" } }'); UPDATE myCollection1 RENAME "address"."street" TO "address"."street name";

SELECT * FROM myCollection1;

SAP HANA JSON Document Store Guide JSON Document Store Statements PUBLIC 27 MYCOLLECTION1

{"firstname": "John", "lastname": "Smith", "age": 45, "address": {"street name": "Dietmar-Hopp-Allee", "city": "Heidelberg"}}

{"firstname": "Amy", "lastname": "Jones", "age": 31, "address": {"street name": "Hauptstraße", "city": "Walldorf"}}

2. The following statements demonstrate the use of JSON object expressions when working with collection tables. The following statement creates a collection called TESTCOLLECTION and inserts JSON documents into it.

CREATE COLLECTION TESTCOLLECTION;

INSERT INTO TESTCOLLECTION VALUES( {"k1" : { "k2" : 30 } } ); INSERT INTO TESTCOLLECTION VALUES( {"k1" : { "k2" : 40 } } );

INSERT INTO TESTCOLLECTION VALUES( {"k1" : { "k2" : 'abc' } } );

Running a SELECT * statement on TESTCOLLECTION returns the following:

{"k1": {"k2": 30}}

{"k1": {"k2": 40}}

{"k1": {"k2": "abc"}}

Execute the following update, which uses JSON object expressions:

UPDATE TESTCOLLECTION SET "k1"."k2" = { "k3" : 'abc' } WHERE "k1"."k2" = 'abc';

Running a SELECT * statement on TESTCOLLECTION now returns the following:

{"k1": {"k2": 30}}

{"k1": {"k2": 40}}

{"k1": {"k2": {"k3": "abc"}}}

5.4.3 DELETE Statement

Deletes documents (entries) from a collection table.

Syntax

DELETE FROM [ WHERE ]

SAP HANA JSON Document Store Guide 28 PUBLIC JSON Document Store Statements Syntax Elements

Specifies the collection table from which data is to be deleted.

::= [[.].]

Specifies values to filter the results.

::=

[ { AND | OR } [...]]

::= {

{ > | >= | < | <= | <> | = }

| BETWEEN AND

| IS NULL | IS { SET | UNSET } }

::=

::= [.[...]]

IS SET | UNSET tests for values that have not been set for the specified key; for example, { "firstname":"", "lastname":"Smith"}.

IS NULL tests for NULL values in the specified key.

specifies a path to a field in a JSON document (for example, "address"."street").

 Note

If no WHERE clause is specified, then all documents in the collection table are deleted.

Description

Deletes JSON documents from a collection table.

DELETE statements on collection tables always return "Affected rows: 0", regardless of how many records are affected.

Examples

The following statements create a collection table, insert five JSON documents into it, and then return the rows where the city is Heidelberg:

CREATE COLLECTION OverSeasContacts;

INSERT INTO OverSeasContacts VALUES ('{ "firstname":"John", "lastname":"Smith", "age":45, "address": { "street": "Dietmar-Hopp-Allee", "city": "Heidelberg" } }');

SAP HANA JSON Document Store Guide JSON Document Store Statements PUBLIC 29 INSERT INTO OverSeasContacts VALUES ('{ "firstname":"Amy", "lastname":"Jones", "age":31, "address": { "city": "Walldorf" } }'); INSERT INTO OverSeasContacts VALUES ('{ "firstname":"Elizabeth", "lastname":"Peterson", "age":19, "address": { "street": "Dietmar-Hopp-Allee", "city": "Heidelberg" } }'); INSERT INTO OverSeasContacts VALUES ('{ "firstname":"Carl", "lastname":"Patel", "age":21, "address": { "street": "", "city": "Walldorf" } }'); INSERT INTO OverSeasContacts VALUES ('{ "firstname":"Roger", "lastname":"Schroeder", "age":77, "address": { "street": "Dietmar-Hopp-Allee", "city": "Heidelberg" } }');

SELECT * FROM OverSeasContacts WHERE "address"."city" = 'Heidelberg';

OVERSEASCONTACTS

{"firstname": "John", "lastname": "Smith", "age": 45, "address": {"street": "Dietmar-Hopp-Allee", "city": "Heidelberg"}}

{"firstname": "Elizabeth", "lastname": "Peterson", "age": 19, "address": {"street": "Dietmar-Hopp-Allee", "city": "Heidelberg"}}

{"firstname": "Roger", "lastname": "Schroeder", "age": 77, "address": {"street": "Dietmar-Hopp-Allee", "city": "Heidelberg"}}

The following statements delete the three rows where the city is Heidelberg, and display what is left in the collection table:

DELETE FROM OverseasContacts WHERE "address"."city" = 'Heidelberg';

SELECT * FROM OverSeasContacts;

OVERSEASCONTACTS

{"firstname": "Amy", "lastname": "Jones", "age": 31, "address": {"city": "Walldorf"}}

{"firstname": "Carl", "lastname": "Patel", "age": 21, "address": {"street": "", "city": "Walldorf"}}

5.5 Data Types

Null Values and Non-Existing Fields

Values may be NULL. NULL values are different from fields that do not exist. Use IS UNSET to select fields that do not exist. Use IS NULL to get fields that are explicitly set NULL or that do not exist.

Example

CREATE COLLECTION Customers;

INSERT INTO Customers VALUES({ "firstName": NULL, "lastName": 'Smith' });

INSERT INTO Customers VALUES({ "lastName": 'Ford' });

SAP HANA JSON Document Store Guide 30 PUBLIC JSON Document Store Statements The following example returns the 'Ford' document:

SELECT * FROM Customers WHERE "firstName" IS UNSET;

The following example returns both documents:

SELECT * FROM Customers WHERE "firstName" IS NULL;

Arrays

Documents may contain arrays.

Example

CREATE COLLECTION withArray;

INSERT INTO withArray VALUES({ "name": 'Sarah', "myArray": [10, 20, 30] });

The numbering starts with 1 according to SQL standard. The following statement returns the document:

SELECT * FROM withArray WHERE "myArray"[1] = 10;

The following statement updates an existing field:

UPDATE withArray SET "myArray"[1] = 11;

The following statement sets "myArray"[5] to 50 and "myArray"[4] implicitly to NULL:

UPDATE withArray SET "myArray"[5] = 50;

The following statement returns {"name": "Sarah", "myArray": [11, 20, 30, null, 50]} :

SELECT * FROM withArray;

Booleans

Documents may contain booleans.

Example

CREATE COLLECTION withBool;

INSERT INTO withBool VALUES({ "name": 'Sarah', "myBool": True });

The following statement returns the document:

SELECT * FROM withBool WHERE "myBool" = TO_JSON_BOOLEAN(True);

You may also set a value to a boolean using the following statement:

UPDATE withBool SET "myBool" = TO_JSON_BOOLEAN(False);

SAP HANA JSON Document Store Guide JSON Document Store Statements PUBLIC 31 5.6 Load/Unload a Collection

A collection table that stores JSON documents can be loaded explicitly into memory instead of loading it on first access. A collection table that stores JSON documents can also be explicitly unloaded from memory.

5.6.1 LOAD Statement

Explicitly loads a collection table that stores JSON documents into memory instead of loading it on first access.

Syntax

LOAD

Syntax Elements

Specifies the name of the collection table to load.

::= [[.].]

Description

Collection tables are automatically loaded into memory upon first access. Use this statement to load the collection table immediately.

Permissions

The use of this statement requires the TABLE ADMIN privilege.

SAP HANA JSON Document Store Guide 32 PUBLIC JSON Document Store Statements 5.6.2 UNLOAD Statement

Explicitly unloads a collection table that stores JSON documents from memory.

Syntax

UNLOAD

Syntax Elements

Specifies the name of the collection table to load.

::= [[.].]

Description

To free up memory, use the UNLOAD statement to unload the collection store from memory. The collection is loaded again on next access.

Using the UNLOAD statement, memory consumed by a collection can be freed. Use LOADED_STATUS in M_COLLECTION_TABLES to check the loaded state. Be aware that the UNLOAD statement only unloads memory artifacts that are currently not in use or no asynchronous processing on the data is pending. Hence, it may happen that you issue UNLOAD, but LOADED_STATUS still reports that the collection is loaded - and in fact, some memory is still being consumed. We are doing this in this manner as unloading would otherwise cause an immediate reload in most situations. Therefore, we treat UNLOAD as a no-op in these cases.

Permissions

The use of this statement requires the TABLE ADMIN privilege.

SAP HANA JSON Document Store Guide JSON Document Store Statements PUBLIC 33 5.7 Native Aggregation

Because of the schema-flexibility of the JSON Document Store, it is required to do explicit type casting when using aggregate functions on fields. Here are two examples that employ TO_BIGINT:

EXAMPLE 1:

CREATE COLLECTION mySum; INSERT INTO mySum VALUES({ "id": 1, "completed": True, "amount": 3 }); INSERT INTO mySum VALUES({ "id": 2, "completed": True, "amount": 1 }); INSERT INTO mySum VALUES({ "id": 3, "completed": False, "amount": 10 });

SELECT SUM(TO_BIGINT("amount")) FROM mySum GROUP BY "completed";

EXAMPLE 2:

CREATE COLLECTION mySumNested; INSERT INTO mySumNested VALUES({ "id": 1, "completed": True, "data": { "amount": 3, "color": 'blue' } }); INSERT INTO mySumNested VALUES({ "id": 2, "completed": True, "data": { "amount": 1, "color": 'red' } }); INSERT INTO mySumNested VALUES({ "id": 3, "completed": False, "data": { "amount": 10, "color": 'blue' } });

SELECT SUM(TO_BIGINT("data"."amount")) FROM mySumNested GROUP BY "completed";

 Note

However aggregation on a field in an array is not supported. So in following examples it is not possible to sum up 1 + 9 in the array "amount":

EXAMPLE 1:

INSERT INTO notPossible1 VALUES({ "id": 1, "completed": True,

"amount": [1, 9] });

EXAMPLE 2:

INSERT INTO notPossible2 VALUES({ "id": 2, "completed": True, "data": [ { "amount": 1 }, { "amount": 9 }

]});

SAP HANA JSON Document Store Guide 34 PUBLIC JSON Document Store Statements 6 Import and Export

You may use a text-based import/export of JSON documents. Here is a syntax example:

CREATE COLLECTION example;

INSERT INTO example VALUES({"key": 5}); EXPORT example INTO '/tmp/exampleExport'; DROP COLLECTION example; IMPORT ALL FROM '/tmp/exampleExport' WITH THREADS 10;

SELECT * FROM example;

If you intend to import JSON files from a different source, which have not been exported using SAP HANA, there may be a limitation. It is required that there is exactly one JSON document per line in the source text file. (This implies that JSON documents are separated by a line break, "\n".) To import a file that contains JSON documents rather than an SAP HANA export of a collection, please use the following syntax:

CREATE COLLECTION contact;

IMPORT FROM CSV FILE '/usr//CB1/home/contact.csv' INTO system.contact WITH batch 10000 threads 50 RECORD DELIMITED BY '\n' FIELD DELIMITED BY ','

optionally enclosed by '""' error log 'data.err' FAIL ON INVALID DATA;

SAP HANA JSON Document Store Guide Import and Export PUBLIC 35 7 Data Type Handling and Schema- Flexibility

Data types are a crucial matter to understand. The following aspects are relevant:

● Data type handling within the Document Store ● Queries touching the schema-flexible Document Store and the schema-strict SAP HANA engines

7.1 Data Types within the Document Store

For each individual field the Document Store stores the associated data type, and each document may have different data types for the same field. In the following example, these three documents may be stored in the same collection:

{"name": 'Paul', "age": 21}

{"name": 'Sarah', "age": '21'}

{"name": 'Mike', "age": '18'}

As you can see, it is valid to have different data types for the same field ("age"). Such a thing may happen in real life when receiving JSON data that for example has been created with different versions of an application. The usage or creation of such JSON data is highly discouraged as it requires the application to properly react to it. The JSON Document Store accepts all JSON data – and when using it, data type really does matter as illustrated in these two examples:

● If you order the two documents from above by "age", it treats all documents with integer values as being smaller than values with string values. In the given example, this will yield 21, '18', '21'. This is probably not what you want. ● If you filter data, data type matters. If you filter with WHERE "age" = 21, you will only get a single JSON document, the one for Paul. And again, this is probably not what you want either. When using comparison functions like >, >=, <= or <, comparison is only executed within the same data types. Other data types are treated as no match. As an example, SELECT * FROM ... WHERE "age" > 20 returns the first document only. There is no implicit casting from integers and strings - this is different from the Column Store. Be aware that any comparisons with NULL yield false, therefore such documents will not be included in a result set. The same is true for non-existing fields that are being used in comparisons. This NULL handling is consistent with the Column Store.

There is a solution for both cases: Use casting, for example to an integer value. There is no implicit casting in the Document Store, and that is for a reason. If there was implicit casting, it probably had to be in strings because strings are the smallest common denominator. But sorting integers as strings would cause different issues again (string '100' is smaller than string '2').

 Note

We recommend using the same data type for all entries of the same field.

SAP HANA JSON Document Store Guide 36 PUBLIC Data Type Handling and Schema-Flexibility 7.2 Crossing Engine Boundaries

Obviously, data types matter. Apparently, with the introduction of the Document Store, we are introducing loose data types into a strict data type SQL world. In the "strict world", data types are fixed and known. This is leveraged in SAP HANA's engines, for example during query compilation. When mixing these two worlds in a single statement, data selected from the Document Store and processed in other engines must have a given type. This is where casting is required. If no casting is made specifically, sting is being used, given its role as common denominator. But there is more that has to be considered. It is important where operations are being executed. For example, an ORDER BY on mixed data types (within the Document Store) may result in a different sort of order than of that in another engine (where all data has the same data type). This is not only true to ORDER BY, but to many functions and filters. Therefore, it has to be made specific whether an operation is to be performed within the Document Store or outside.

A join with the Column Store shall serve as an example. Let's revisit the join from the introductory chapter.

WITH myView AS (SELECT "name", "address"."city" as "city" FROM Customers)

SELECT cst."name", cst."age", myView."city"

FROM myView INNER JOIN SomeColumnStoreTable AS cst ON myView."name" = cst."name";

Here, WITH denotes the definition of an implicit view. That is a handy way to define two queries in one. It can be compared with a sub-query or with the creation of a view, just that it is not added to the catalog. The implicit view defines the data that is requested from the Document Store, that data being in a tabular format with denoted columns. Here "name" and "city" will be the columns of the intermediate results. Given that there is no cast, the data will be returned as strings, which is the proper data type for the given data of course. Use TO_BIGINT and the like for data type casts. A crucial aspect is filtering. The closer a filter is to the data, the smaller the intermediate results. For good performance, add filters ideally within the definition of the implicit view.

Be aware that it is also possible to create "real" views using "CREATE VIEW" on collections. These come typically with a significant drawback. If you filter on a view, that filter is not being pushed down. This may cause performance issues for large data sets.

SAP HANA JSON Document Store Guide Data Type Handling and Schema-Flexibility PUBLIC 37 8 Changes from SPS 03 to SPS 04

In SPS 03, it was not allowed to have dots in identifiers as dots were reserved as a separator for path expressions. Unfortunately, the dot-handling for paths was not consistent.

SPS 04 allows queries like this:

SELECT * FROM myCollection WHERE "address"."city.name" = 'Heidelberg';

Here, city.name is an identifier with a dot. This usage is discouraged however. But this might be required in scenarios where identifiers have a technical notion or are generated, like:

SELECT * FROM display WHERE "[mainview].[properties]" = 'collapsed';

In SPS 03 the following two statements are basically identical, but different in SPS 04:

SELECT * FROM myCollection WHERE "address"."city" = 'Heidelberg';

SELECT * FROM myCollection WHERE "address.city" = 'Heidelberg';

If your existing application uses identifiers like this, you will need to adapt it. If you do not use double-quotes though, no change is required. The handling of statements like the following example has not been changed:

SELECT * FROM myCollection WHERE address.city = 'Heidelberg';

SAP HANA JSON Document Store Guide 38 PUBLIC Changes from SPS 03 to SPS 04 9 Escape Sequences and Unicode in the SAP HANA Document Store

JSON offers the specification of escape sequences in strings. The following example is valid JSON:

{ "message": "hello\nworld"}

According to json.org, a string is any Unicode character except ", \ or control characters. The following escape sequences are valid:

Escape Sequence Description

\" quotation mark

\\ backslash

\/ forward slash

\b backspace

\f form feed

\n newline

\ carriage return

\t horizontal tab

\u and four hexadecimal digits Unicode code point

The SAP HANA Document Store supports these escape sequences. This document shall explain how it is to be used.

9.1 Background

SAP HANA Document Store offers two interfaces to insert JSON:

● JSON String INSERT INTO myCollection VALUES('{"myIdentifier": "myStringLiteral"}'); ● Object Expression INSERT INTO myCollection VALUES({"myIdentifier": 'myStringLiteral'});

Note that the JSON string interface requires valid JSON, whereas the Object Expression is an SQL feature. The latter is deeply nested and constructed similarly to JSON, but its identifiers follow the rules for SQL identifiers. That is, identifiers are to be written in double quotes. If omitted, they will be automatically converted to upper- case. Also, values follow the SQL syntax for values and literals. Therefore, string literals are to be specified using single quotes, which differ from the known JSON syntax.

SAP HANA JSON Document Store Guide Escape Sequences and Unicode in the SAP HANA Document Store PUBLIC 39 JSON's escape sequences are solely supported in the string interface. Here is a usage example:

INSERT INTO myCollection VALUES('{"message": "hello\"world"}'); -- insert with \"

SELECT * FROM myCollection; -- returns {"message": "hello\"world"} as a JSON string

This is likely not surprising so far – the string interface accepts JSON, SELECT * returns JSON. But the behavior is different when working on the data as values. Here are two examples. Keep in mind that the data has been inserted using \". But \" really stands for " as a value.

SELECT * FROM myCollection WHERE "message" = 'hello"world'; -- returns {"message": "hello\"world"}

SELECT * FROM myCollection WHERE "message" = 'hello\"world'; -- returns an empty result set

As you can see, when using a field value in the WHERE clause, the actual non-escaped value is required. It will return the requested document as a JSON string. The JSON string in turn is formatted as JSON and therefore it prints \".

If you do not request the document as JSON but an individual field, the same behavior can be observed.

SELECT "message" FROM myCollection; -- returns the string hello"world

To sum up, if you insert or obtain JSON, the escape sequence is expected and obtained respectively. If you use the Document Store to work on its data directly (that is in a projection, in a WHERE clause or with an Object Expression), in the absence of a JSON representation, all values are to be used in their non-escaped, "direct" form.

As a rule of thumb, always stay with one representation and only switch between them when needed. The JSON representation is only supported for INSERT and SELECT *. Object Expression, filters and the like use values.

Example 1

INSERT INTO ValuesOnly ({"message": 'hello"world', "someValue": 1});

SELECT "message", "someValue" WHERE "message" = 'hello"world'; -- this returns the document with hello"world in the message column.

Notice that there is no escaping involved - it works as if it was on a Column Store table. Only the usage of JSON introduces the need to handle escaping. Here is the same example again, inserting and selecting JSON.

Example 2

INSERT INTO ValuesOnly ('{"message": "hello\"world", "someValue": 1}');

SELECT * WHERE "message" = 'hello"world'; -- this returns the following: {"message": "hello\"world", "someValue": 1}

If you use the Object Expression and try to insert an escape sequence, that escape sequence is not recognized as an escape sequence, but as a value – which is likely not what you want. Here is an example:

INSERT INTO myCollection VALUES({"message": 'hello\"world'}); -- not what it might seem to be

This actually stores the value hello\"world. If you select the data as JSON, it will actually escape the escape sequence:

SELECT * FROM myCollection; -- returns {"message": "hello\\\"world"};

SAP HANA JSON Document Store Guide 40 PUBLIC Escape Sequences and Unicode in the SAP HANA Document Store Character "

Insert as string INSERT INTO ... VALUES('{"message": "hello\"world"}')

SELECT * FROM ... {"message": "hello\"world"}

Insert as Object Expression INSERT INTO ... VALUES({"message": 'hello"world'})

SELECT "message" FROM ... hello"world

Filter WHERE "message" = 'hello"world'

These rules apply to \", \\, \b, \f, \n, \r, and \t. \/, and \u are handled in the next chapters.

9.2 Special Case "Forward Slash"

The forward slash can easily be written without any escaping in JSON. The following statements are valid:

{"message": "hello/world"}

{"message": "hello\/world"}

When inserting a JSON document with \/ as escape sequence, it stores it as /. When inserting a JSON document with /, it is also being stored as /. In other words, both ways of insertion yield the same document in the Document Store. When printing the document, it just prints / and not \/ as you can see in the following table.

Character /

Insert as string The following statements are valid: ● INSERT INTO ... VALUES('{"message": "hello/world"}') ● INSERT INTO ... VALUES('{"message": "hello\/world"}')

SELECT * FROM ... {"message": "hello/world"}

Insert as Object Expression INSERT INTO ... VALUES({"message": 'hello/world'})

SELECT "message" FROM ... hello/world

Filter "message" = 'hello/world'

SAP HANA JSON Document Store Guide Escape Sequences and Unicode in the SAP HANA Document Store PUBLIC 41 9.3 Special Case "Unicode"

JSON allows Unicode characters to be written directly without escaping. This is true for Unicode code points from hexadecimal 0020 to 10ffff. Also, Unicode codepoints may be written in the \u syntax.

Here is an example with Latin characters known from ASCII: Code point 0065 is the letter e. Just like in the example with the forward slash, two different ways of writing yield the same document. The following statements produce the same document:

INSERT INTO myCollection VALUES('{"message": "hello world"}')

INSERT INTO myCollection VALUES('{"message": "h\u0065llo world"}')

INSERT INTO myCollection VALUES({"message": 'hello world'})

Be aware that the Unicode representation is the internal representation. This means that even if you insert with \u0065, you will not find the document when filtering with \u0065. Filtering means that the value is being used for comparison and the value of \u0065 is e.

Character Unicode

Insert as string ● INSERT INTO ... VALUES('{"message": "h\u0065llo world"}') ● INSERT INTO ... VALUES('{"message": "hello world"}')

SELECT * FROM ... {"message": "hello world"}

Insert as Object Expression INSERT INTO ... VALUES({"message": 'hello world'})

SELECT "message" FROM ... hello world

Filter WHERE "message" = 'hello world'

As mentioned above, Unicode characters may be inserted starting at hexadecimal 0020. But even if carriage returns and other control characters cannot be inserted using ordinary characters, they may be inserted using the \u syntax. This is a valid statement:

INSERT INTO myCollection VALUES('{"message": "hello\u0002world"}')

When the document is being returned as JSON, the character is printed again with its escape sequence, in this case \u0002. This is different for all characters with code points above 0020. Be aware that the code points for backspace, tabulator, newline, form feed and carriage return are not printed in the \u syntax, but instead as \b, \t, \n, \f and \r.

Even though control characters are not allowed in JSON strings, it is possible to query the Document Store for such values. But this requires that you specify its binary UTF-8 encoding. Be aware that this is not supported for \u0000 and for planes other than Plane 0. UTF-16 may be specified in the input JSON string:

INSERT INTO myCollection VALUES('{"message": "hello\uD800\uDF36world"}')

SAP HANA JSON Document Store Guide 42 PUBLIC Escape Sequences and Unicode in the SAP HANA Document Store \uD800\uDF36 identifies code point 10336 from plane 1. It yields:

SELECT * FROM myCollection; -- returns {"message": "helloworld"}

9.4 Identifiers

All examples have been with special characters and Unicode in string values, but it is also legitimate to have them in identifiers.

Example

INSERT INTO myCollection VALUES('{"mes\\sage": "hello world"}');

All rules for string values also apply to string identifiers.

9.5 Corrections

Prior to SAP HANA 2.0 SPS 03 Revision 35, the storage of UTF-16 using two pairs of four hexadecimal escape sequences may have led to an incorrect encoding. Also, the usage of Unicode escape sequences in JSON identifiers may have led to an incorrect encoding.

Since SAP HANA 2.0 SPS 03 Revision 36, the usage of \u0000 to denote a NULL byte is prohibited. Documents that are already stored remain valid, but no new ones may be inserted. Additionally, \u0000 cannot be used as a value in the SET clause of an update. This is consistent with the prohibition of NULL bytes in the other SAP HANA stores.

SAP HANA JSON Document Store Guide Escape Sequences and Unicode in the SAP HANA Document Store PUBLIC 43 Important Disclaimer for Features in SAP HANA

For information about the capabilities available for your license and installation scenario, refer to the Feature Scope Description for SAP HANA.

SAP HANA JSON Document Store Guide 44 PUBLIC Important Disclaimer for Features in SAP HANA Important Disclaimers and Legal Information

Hyperlinks

Some links are classified by an icon and/or a mouseover text. These links provide additional information. About the icons:

● Links with the icon : You are entering a Web site that is not hosted by SAP. By using such links, you agree (unless expressly stated otherwise in your agreements with SAP) to this:

● The content of the linked-to site is not SAP documentation. You may not infer any product claims against SAP based on this information. ● SAP does not agree or disagree with the content on the linked-to site, nor does SAP warrant the availability and correctness. SAP shall not be liable for any damages caused by the use of such content unless damages have been caused by SAP's gross negligence or willful misconduct.

● Links with the icon : You are leaving the documentation for that particular SAP product or service and are entering a SAP-hosted Web site. By using such links, you agree that (unless expressly stated otherwise in your agreements with SAP) you may not infer any product claims against SAP based on this information.

Beta and Other Experimental Features

Experimental features are not part of the officially delivered scope that SAP guarantees for future releases. This means that experimental features may be changed by SAP at any time for any reason without notice. Experimental features are not for productive use. You may not demonstrate, test, examine, evaluate or otherwise use the experimental features in a live operating environment or with data that has not been sufficiently backed up. The purpose of experimental features is to get feedback early on, allowing customers and partners to influence the future product accordingly. By providing your feedback (e.g. in the SAP Community), you accept that intellectual property rights of the contributions or derivative works shall remain the exclusive property of SAP.

Example Code

Any software coding and/or code snippets are examples. They are not for productive use. The example code is only intended to better explain and visualize the syntax and phrasing rules. SAP does not warrant the correctness and completeness of the example code. SAP shall not be liable for errors or damages caused by the use of example code unless damages have been caused by SAP's gross negligence or willful misconduct.

Gender-Related Language

We try not to use gender-specific word forms and formulations. As appropriate for context and readability, SAP may use masculine word forms to refer to all genders.

SAP HANA JSON Document Store Guide Important Disclaimers and Legal Information PUBLIC 45 www.sap.com/contactsap

© 2019 SAP SE or an SAP affiliate company. All rights reserved.

No part of this publication may be reproduced or transmitted in any form or for any purpose without the express permission of SAP SE or an SAP affiliate company. The information contained herein may be changed without prior notice.

Some software products marketed by SAP SE and its distributors contain components of other software vendors. National product specifications may vary.

These materials are provided by SAP SE or an SAP affiliate company for informational purposes only, without representation or warranty of any kind, and SAP or its affiliated companies shall not be liable for errors or omissions with respect to the materials. The only warranties for SAP or SAP affiliate company products and services are those that are set forth in the express warranty statements accompanying such products and services, if any. Nothing herein should be construed as constituting an additional warranty.

SAP and other SAP products and services mentioned herein as well as their respective logos are trademarks or registered trademarks of SAP SE (or an SAP affiliate company) in Germany and other countries. All other product and service names mentioned are the trademarks of their respective companies.

Please see https://www.sap.com/about/legal/trademark.html for additional trademark information and notices.

THE BEST RUN