166
Oracle® NoSQL Database Getting Started with SQL for Oracle NoSQL Database Release 19.1 E85380-08 April 2019

Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

  • Upload
    others

  • View
    67

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Oracle® NoSQL DatabaseGetting Started with SQL for Oracle NoSQLDatabase

Release 19.1E85380-08April 2019

Page 2: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Oracle NoSQL Database Getting Started with SQL for Oracle NoSQL Database, Release 19.1

E85380-08

Copyright © 2011, 2019, Oracle and/or its affiliates. All rights reserved.

This software and related documentation are provided under a license agreement containing restrictions onuse and disclosure and are protected by intellectual property laws. Except as expressly permitted in yourlicense agreement or allowed by law, you may not use, copy, reproduce, translate, broadcast, modify,license, transmit, distribute, exhibit, perform, publish, or display any part, in any form, or by any means.Reverse engineering, disassembly, or decompilation of this software, unless required by law forinteroperability, is prohibited.

The information contained herein is subject to change without notice and is not warranted to be error-free. Ifyou find any errors, please report them to us in writing.

If this is software or related documentation that is delivered to the U.S. Government or anyone licensing it onbehalf of the U.S. Government, then the following notice is applicable:

U.S. GOVERNMENT END USERS: Oracle programs, including any operating system, integrated software,any programs installed on the hardware, and/or documentation, delivered to U.S. Government end users are"commercial computer software" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations. As such, use, duplication, disclosure, modification, and adaptation of theprograms, including any operating system, integrated software, any programs installed on the hardware,and/or documentation, shall be subject to license terms and license restrictions applicable to the programs.No other rights are granted to the U.S. Government.

This software or hardware is developed for general use in a variety of information management applications.It is not developed or intended for use in any inherently dangerous applications, including applications thatmay create a risk of personal injury. If you use this software or hardware in dangerous applications, then youshall be responsible to take all appropriate fail-safe, backup, redundancy, and other measures to ensure itssafe use. Oracle Corporation and its affiliates disclaim any liability for any damages caused by use of thissoftware or hardware in dangerous applications.

Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks oftheir respective owners.

Intel and Intel Xeon are trademarks or registered trademarks of Intel Corporation. All SPARC trademarks areused under license and are trademarks or registered trademarks of SPARC International, Inc. AMD, Opteron,the AMD logo, and the AMD Opteron logo are trademarks or registered trademarks of Advanced MicroDevices. UNIX is a registered trademark of The Open Group.

This software or hardware and documentation may provide access to or information about content, products,and services from third parties. Oracle Corporation and its affiliates are not responsible for and expresslydisclaim all warranties of any kind with respect to third-party content, products, and services unless otherwiseset forth in an applicable agreement between you and Oracle. Oracle Corporation and its affiliates will not beresponsible for any loss, costs, or damages incurred due to your access to or use of third-party content,products, or services, except as set forth in an applicable agreement between you and Oracle.

Page 3: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Contents

Preface

Conventions Used in This Book viii

1 Introduction to SQL for Oracle NoSQL Database

Part I Introductory Examples

2 Simple SELECT Queries

SQLBasicExamples Script 2-1

Starting the SQL Shell 2-2

Choosing column data 2-2

Substituting column names for a query 2-3

Computing values for new columns 2-4

Identifying tables and their columns 2-4

Filtering Results 2-5

Grouping Results 2-7

Ordering Results 2-7

Limiting and Offsetting Results 2-9

Using External Variables 2-10

3 Working with complex data

SQLAdvancedExamples Script 3-1

Working with Timestamps 3-4

Working With Arrays 3-5

Working with Records 3-11

Using ORDER BY to Sort Results 3-12

Working With Maps 3-13

Using the size() Function 3-16

iii

Page 4: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

4 Working with JSON

SQLJSONExamples Script 4-1

Basic Queries 4-4

Using WHERE EXISTS with JSON 4-6

Seeking NULLS in Arrays 4-7

Examining Data Types JSON Columns 4-8

Using Map Steps with JSON Data 4-11

Casting Datatypes 4-12

Using Searched Case 4-13

5 Working With GeoJSON Data

Geodetic Coordinates 5-1

GeoJSON Data Definitions 5-2

Searching GeoJSON Data 5-5

6 Working With Indexes

Basic Indexing 6-1

Using Index Hints 6-2

Complex Indexes 6-3

Multi-Key Indexes 6-4

Indexing JSON Data 6-9

7 Working with Table Rows

Adding Table Rows using INSERT and UPSERT 7-1

Modifying Table Rows using UPDATE Statements 7-4

Example Data 7-4

Changing Field Values 7-5

Modifying Array Values 7-7

Adding Elements to an Array 7-7

Changing an Existing Element in an Array 7-9

Removing Elements from Arrays 7-10

Modifying Map Values 7-12

Removing Elements from a Map 7-14

Adding Elements to a Map 7-14

Updating Existing Map Elements 7-17

Managing Time to Live Values 7-21

Avoiding the Read-Modify-Write Cycle 7-23

iv

Page 5: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Part II Language Definition

8 The SQL for Oracle NoSQL Database Data Model

Example Data 8-1

Data Types and Values 8-2

Wildcard Types and JSON Data 8-3

JSON Data 8-4

Timestamp 8-4

Timestamp Functions 8-5

Type Hierarchy 8-6

Subtype-Substitution Rule Exceptions 8-8

SQL for Oracle NoSQL Database Sequences 8-8

Sequence Concatenation Function 8-9

9 SQL for Oracle NoSQL Database Queries

Select-From-Where (SFW) Expressions 9-1

SELECT Clause 9-2

SELECT Clause Hints 9-3

FROM Clause 9-3

WHERE Clause 9-4

GROUP BY Clause 9-4

Aggregate Functions 9-5

ORDER BY Clause 9-8

Comparison Rules 9-8

OFFSET Clause 9-9

LIMIT Clause 9-9

Joins 9-10

NESTED TABLES Clause 9-10

Examples 9-11

10

Expressions

Path Expressions 10-1

Field Step Expressions 10-2

Map Filter Step Expressions 10-3

Array Filter Step Expressions 10-3

Array Slice Step Expressions 10-4

Constant Expressions 10-5

Column Reference Expression 10-5

v

Page 6: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Variable Reference Expression 10-6

Searched Case Expressions 10-6

Cast Expressions 10-7

Sequence Transform Expression 10-9

11

Operators

Logical Operators 11-1

Value Comparison Operators 11-1

Sequence Comparison Operators 11-3

IS NULL Operator 11-3

Exists Operator 11-4

Is-Of-Type Operator 11-4

12

Constructors

Array Constructors 12-1

Map Constructors 12-1

13

Built-in Functions

Time to Live Functions 13-1

Time Functions 13-2

14

SQL Statements

Insert Statement Syntax 14-1

Update Statement Syntax 14-3

Update Clauses 14-3

SET Clause 14-4

ADD Clause 14-5

PUT Clause 14-5

REMOVE Clause 14-6

SET TTL Clause 14-6

A Introduction to the SQL for Oracle NoSQL Database Shell

Running the SQL Shell A-1

Configuring the shell A-2

Shell Utility Commands A-3

connect A-3

consistency A-3

vi

Page 7: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

describe A-4

durability A-5

exit A-5

help A-6

history A-6

import A-6

load A-7

mode A-7

output A-11

page A-11

show faults A-11

show namespaces A-11

show query A-12

show roles A-12

show tables A-12

show users A-14

timeout A-14

timer A-14

verbose A-15

version A-15

vii

Page 8: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Preface

This document is intended to provide a rapid introduction to the SQL for OracleNoSQL Database and related concepts. SQL for Oracle NoSQL Database is an easyto use SQL-like language that supports read-only queries and data definition (DDL)statements. This document focuses on the query part of the language. For a moredetailed description of the language (both DDL and query statements) see the SQL forOracle NoSQL Database Specification.

This book is aimed at developers who are looking to manipulate Oracle NoSQLDatabase data using a SQL-like query language. Knowledge of standard SQL is notrequired but it does allow you to easily learn SQL for Oracle NoSQL Database.

Conventions Used in This BookThe following typographical conventions are used within this manual:

Information that you are to type literally is presented in monospaced font.

Variable or non-literal text is presented in italics. For example: "Go to your KVHOMEdirectory."

Case-insensitive keywords, like SELECT, FROM, WHERE, ORDER BY, are presentedin UPPERCASE.

Case sensitive keywords, like the function size(item) are presented in lowercase.

Note:

Finally, notes of special interest are represented using a note block such asthis.

Preface

viii

Page 9: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

1Introduction to SQL for Oracle NoSQLDatabase

Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-likeinterface to Oracle NoSQL Database that can be used from a command line interface,scripts, or from the Oracle NoSQL Database Java Table Driver. The SQL for OracleNoSQL Database data model supports flat relational data, hierarchical typed (schema-full) data, and schema-less JSON data. SQL for Oracle NoSQL Database is designedto handle all such data in a seamless fashion without any "impedance mismatch"among the different sub models.

For information on the command line shell you can use to run SQL for Oracle NoSQLDatabase queries, see Introduction to the SQL for Oracle NoSQL Database Shell. Forinformation on executing SQL for Oracle NoSQL Database queries from the OracleNoSQL Database Java Table Driver, see the Oracle NoSQL Database Getting Startedwith the Table API manual.

This book is broken into two parts:

• Part I provides an examples-based introduction to the language. It begins here: Introductory Examples

• Part II provides a textual description of the language. It begins here: LanguageDefinition

1-1

Page 10: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Part IIntroductory Examples

This part provides an examples-based introduction to SQL for Oracle NoSQLDatabase. For a textual description of the language, please see Language Definition.

Page 11: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

2Simple SELECT Queries

This section presents examples of simple queries for relational data. To follow alongwith the examples, get the Examples download from here and run theSQLBasicExamples script found in the sql folder. The script creates the table asshown, and imports the data.

SQLBasicExamples ScriptThe script SQLBasicExamples creates the following table:

CREATE TABLE Users ( id integer, firstname string, lastname string, age integer, income integer, primary key (id));

The script also load data into the Users table with the following rows (shown here inJSON format):

{ "id":1, "firstname":"David", "lastname":"Morrison", "age":25, "income":100000,}

{ "id":2, "firstname":"John", "lastname":"Anderson", "age":35, "income":100000,}

{ "id":3, "firstname":"John", "lastname":"Morgan", "age":38, "income":null,}

{

2-1

Page 12: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

"id":4, "firstname":"Peter", "lastname":"Smith", "age":38, "income":80000,}

{ "id":5, "firstname":"Dana", "lastname":"Scully", "age":47, "income":400000,}

You run the SQLBasicExamples script using the load command:

> cd <installdir>/examples/sql> java -jar <KVHOME>/lib/sql.jar -helper-hosts <host>:<port> \-store <storename> load \-file <KVHOME>/examples/sql/SQLBasicExamples.cli

Starting the SQL ShellYou can run SQL queries and execute DDL statements directly from the SQL shell.This is described in Introduction to the SQL for Oracle NoSQL Database Shell. To runthe queries shown in this document, start the SQL shell as follows:

java -jar KVHOME/lib/sql.jar-helper-hosts node01:5000 -store kvstoresql->

Note:

This document shows examples displayed in COLUMN mode, although thedefault output type is JSON. Use the mode command to toggle betweenCOLUMN and JSON (or JSON pretty) output.

Choosing column dataYou can choose columns from a table. To do so, list the names of the desired tablecolumns after SELECT in the statement, before noting the table after the FROMclause.

The FROM clause can name only one table. To retrieve data from a child table, usedot notation, such as parent.child.

Chapter 2Starting the SQL Shell

2-2

Page 13: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

To choose all table columns, use the asterisk (*) wildcard character as follows:

sql-> SELECT * FROM Users;

The SELECT statement displays these results:

+----+-----------+----------+-----+--------+ | id | firstname | lastname | age | income | +----+-----------+----------+-----+--------+ | 3 | John | Morgan | 38 | NULL | | 4 | Peter | Smith | 38 | 80000 | | 2 | John | Anderson | 35 | 100000 | | 5 | Dana | Scully | 47 | 400000 | | 1 | David | Morrison | 25 | 100000 | +----+-----------+----------+-----+--------+

5 rows returned

To choose specific column(s) from the table Users, include the column names as acomma-separated list in the SELECT statement:

sql-> SELECT firstname, lastname, age FROM Users; +-----------+----------+-----+ | firstname | lastname | age | +-----------+----------+-----+ | John | Morgan | 38 | | David | Morrison | 25 | | Dana | Scully | 47 | | Peter | Smith | 38 | | John | Anderson | 35 | +-----------+----------+-----+

5 rows returned

Substituting column names for a queryYou can use a different name for a column during a SELECT statement. Substituting aname in a query does not change the column name, but uses the substitute in thereturned data returned. In the next example, the query substitutes Surname for theactual column name lastname, by using the actual-name AS substitute-name clause,in the SELECT statement.

sql-> SELECT lastname AS Surname FROM Users; +----------+ | Surname | +----------+ | Scully | | Smith | | Morgan | | Anderson | | Morrison |

Chapter 2Substituting column names for a query

2-3

Page 14: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

+----------+

5 rows returned

Computing values for new columnsThe SELECT statement can contain computational expressions based on the valuesof existing columns. For example, in the next statement, you select the values of onecolumn, income, divide each value by 12, and display the output in another column.The SELECT statement can use almost any type of expression. If more than one valueis returned, the items are inserted into an array.

This SELECT statement uses the yearly income values divided by 12 to calculate thecorresponding values for monthlysalary:

sql-> SELECT id, lastname, income, income/12AS monthlysalary FROM users; +----+----------+--------+---------------+ | id | lastname | income | monthlysalary | +----+----------+--------+---------------+ | 2 | Anderson | 100000 | 8333 | | 1 | Morrison | 100000 | 8333 | | 5 | Scully | 400000 | 33333 | | 4 | Smith | 80000 | 6666 | | 3 | Morgan | NULL | NULL | +----+----------+--------+---------------+

5 rows returned

This SELECT statement performs an addition operation that adds a bonus of 5000 toincome to return salarywithbonus:

sql-> SELECT id, lastname, income, income+5000AS salarywithbonus FROM users; +----+----------+--------+-----------------+ | id | lastname | income | salarywithbonus | +----+----------+--------+-----------------+ | 4 | Smith | 80000 | 85000 | | 1 | Morrison | 100000 | 105000 | | 5 | Scully | 400000 | 405000 | | 3 | Morgan | NULL | NULL | | 2 | Anderson | 100000 | 105000 | +----+----------+--------+-----------------+

5 rows returned

Identifying tables and their columnsThe FROM clause can contain one table only (that is, joins are not supported). Thetable is specified by its name, which may be followed by an optional alias. The tablecan be referenced in the other clauses either by its name or its alias. As we will seelater, sometimes the use of the table name or alias is mandatory. However, for table

Chapter 2Computing values for new columns

2-4

Page 15: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

columns, the use of the table name or alias is optional. For example, here are threeways to write the same query:

sql-> SELECT Users.lastname, age FROM Users; +----------+-----+ | lastname | age | +----------+-----+ | Scully | 47 | | Smith | 38 | | Morgan | 38 | | Anderson | 35 | | Morrison | 25 | +----------+-----+

5 rows returned

To identify the table Users with the alias u:

sql-> SELECT lastname, u.age FROM Users u ;

The keyword AS can optionally be used before an alias. For example, to identify thetable Users with the alias People:

sql-> SELECT People.lastname, People.age FROM Users AS People;

Filtering ResultsYou can filter query results by specifying a filter condition in the WHERE clause.Typically, a filter condition consists of one or more comparison expressions connectedthrough logical operators AND or OR. The comparison operators are also supported:=, !=, >, >=, <, and <= .

This query filters results to return only users whose first name is John:

sql-> SELECT id, firstname, lastname FROM Users WHERE firstname = "John"; +----+-----------+----------+ | id | firstname | lastname | +----+-----------+----------+ | 3 | John | Morgan | | 2 | John | Anderson | +----+-----------+----------+

2 rows returned

To return users whose calculated monthlysalary is greater than 6000:

sql-> SELECT id, lastname, income, income/12 AS monthlysalaryFROM Users WHERE income/12 > 6000; +----+----------+--------+---------------+ | id | lastname | income | monthlysalary | +----+----------+--------+---------------+ | 5 | Scully | 400000 | 33333 |

Chapter 2Filtering Results

2-5

Page 16: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| 4 | Smith | 80000 | 6666 | | 2 | Anderson | 100000 | 8333 | | 1 | Morrison | 100000 | 8333 | +----+----------+--------+---------------+

5 rows returned

To return users whose age is between 30 and 40 or whose income is greater than100,000:

sql-> SELECT lastname, age, income FROM Users WHERE age >= 30 and age <= 40 or income > 100000; +----------+-----+--------+ | lastname | age | income | +----------+-----+--------+ | Smith | 38 | 80000 | | Morgan | 38 | NULL | | Anderson | 35 | 100000 | | Scully | 47 | 400000 | +----------+-----+--------+

4 rows returned

You can use parenthesized expressions to alter the default precedence amongoperators. For example:

To return the users whose age is greater than 40 and either their age is less than 30 ortheir income is greater or equal than 100,000:

sql-> SELECT id, lastName FROM Users WHERE(income >= 100000 or age < 30) and age > 40; +----+----------+ | id | lastName | +----+----------+ | 5 | Scully | +----+----------+

1 row returned

You can use the IS NULL condition to return results where a field column value is setto SQL NULL (SQL NULL is used when a non-JSON field is set to null):

sql-> SELECT id, lastname from Users WHERE income IS NULL; +----+----------+ | id | lastname | +----+----------+ | 3 | Morgan | +----+----------+

1 row returned

Chapter 2Filtering Results

2-6

Page 17: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

You can use the IS NOT NULL condition to return column values that contain non-nulldata:

sql-> SELECT id, lastname from Users WHERE income IS NOT NULL; +----+----------+ | id | lastname | +----+----------+ | 4 | Smith | | 1 | Morrison | | 5 | Scully | | 2 | Anderson | +----+----------+

4 rows returned

Grouping ResultsUse the GROUP BY clause to group the results by one or more table columns.Typically, a GROUP BY clause is used in conjunction with an aggregate expressionsuch as COUNT, SUM, and AVG.

Note:

You can use the GROUP BY clause only if there exists an index that sortsthe rows by the grouping columns.

For detailed information on GROUP BY and aggregate functions, see GROUP BYClause.

For example, this query returns the average income of users, based on their age.

sql-> SELECT age, AVG(income) FROM Users GROUP BY age; +-------+-------------+ | age | AVG(income) | +-------+-------------+ | 25 | 100000 | | 35 | 100000 | | 38 | 80000 | | 47 | 400000 | +-------+-------------+

4 rows returned

Ordering ResultsUse the ORDER BY clause to order the results by a primary key column or a non-primary key column.

Chapter 2Grouping Results

2-7

Page 18: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Note:

You can use ORDER BY only if you are selecting by the table's primary key,or if there is an index that sorts the table's rows in the desired order.

To order by using a primary key column (id), specify the sort column in the ORDER BYclause:

sql-> SELECT id, lastname FROM Users ORDER BY id; +----+----------+ | id | lastname | +----+----------+ | 1 | Morrison | | 2 | Anderson | | 3 | Morgan | | 4 | Smith | | 5 | Scully | +----+----------+

5 rows returned

To order by a non-primary key column, first create an index on the column of interest.For example, to use column lastname for ordering, create an index on that column,before using it in your ORDER BY clause:

sql-> CREATE INDEX idx1 on Users(lastname);Statement completed successfullysql-> SELECT id, lastname FROM Users ORDER BY lastname; +----+----------+ | id | lastname | +----+----------+ | 2 | Anderson | | 3 | Morgan | | 1 | Morrison | | 5 | Scully | | 4 | Smith | +----+----------+

5 rows returned

Using this example data, you can order by more than one column if you create anindex on the columns. (If our table had used more than one column for its primary key,then you can order by multiple columns using the primary keys.) For example, to orderusers by age and income.

sql-> CREATE INDEX idx2 on Users(age, income);Statement completed successfullysql-> SELECT id, lastname, age, income FROM Users ORDER BY age, income; +----+----------+-----+--------+ | id | lastname | age | income | +----+----------+-----+--------+

Chapter 2Ordering Results

2-8

Page 19: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| 1 | Morrison | 25 | 100000 | | 2 | Anderson | 35 | 100000 | | 4 | Smith | 38 | 80000 | | 3 | Morgan | 38 | NULL | | 5 | Scully | 47 | 400000 | +----+----------+-----+--------+

5 rows returned

Creating a single index from two columns in the order you use them (age, income inthis example), has some limits. The first column name (age) becomes the main sortitem for the new index. You can use idx2 index to order by age only, but neither byincome only, nor by income first and age second.

sql-> SELECT id, lastname, age from Users ORDER BY age; +----+----------+-----+ | id | lastname | age | +----+----------+-----+ | 1 | Morrison | 25 | | 2 | Anderson | 35 | | 4 | Smith | 38 | | 3 | Morgan | 38 | | 5 | Scully | 47 | +----+----------+-----+

5 rows returned

To learn more about indexes see Working With Indexes.

By default, sorting is performed in ascending order. To sort in descending order usethe DESC keyword in the ORDER BY clause:

sql-> SELECT id, lastname FROM Users ORDER BY id DESC; +----+----------+ | id | lastname | +----+----------+ | 5 | Scully | | 4 | Smith | | 3 | Morgan | | 2 | Anderson | | 1 | Morrison | +----+----------+

5 rows returned

Limiting and Offsetting ResultsUse the LIMIT clause to limit the number of results returned from a SELECTstatement. For example, if there are 1000 rows in the Users table, limit the number of

Chapter 2Limiting and Offsetting Results

2-9

Page 20: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

rows to return by specifying a LIMIT value. For example, this statement returns the firstfour ID rows from the table:

sql-> SELECT * from Users ORDER BY id LIMIT 4; +----+-----------+----------+-----+--------+ | id | firstname | lastname | age | income | +----+-----------+----------+-----+--------+ | 1 | David | Morrison | 25 | 100000 | | 2 | John | Anderson | 35 | 100000 | | 3 | John | Morgan | 38 | NULL | | 4 | Peter | Smith | 38 | 80000 | +----+-----------+----------+-----+--------+

4 rows returned

To return only results 3 and 4 from the 10000 rows use the LIMIT clause to indicate 2values, and the OFFSET clause to specify where the offset begins (after the first tworows). For example:

sql-> SELECT * from Users ORDER BY id LIMIT 2 OFFSET 2; +----+-----------+----------+-----+--------+ | id | firstname | lastname | age | income | +----+-----------+----------+-----+--------+ | 3 | John | Morgan | 38 | NULL | | 4 | Peter | Smith | 38 | 80000 | +----+-----------+----------+-----+--------+

2 rows returned

Note:

We recommend using LIMIT and OFFSET with an ORDER BY clause.Otherwise, the results are returned in a random order, producingunpredictable results.

Using External VariablesUsing external variables lets a query to written and compiled once, and then runmultiple times with different values for the external variables. Binding the externalvariables to specific values is done through APIs (see the Getting Started with theTable API manual), which you use before executing the query.

You must declare external variables in your SQL query before referencing them in theSELECT statement. For example:

DECLARE $age integer;SELECT firstname, lastname, ageFROM UsersWHERE age > $age;

Chapter 2Using External Variables

2-10

Page 21: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

If the variable $age is set to value 39, the result of the above query is:

+-----------+----------+-----+| firstname | lastname | age |+-----------+----------+-----+| Dana | Scully | 47 |+-----------+----------+-----+

Chapter 2Using External Variables

2-11

Page 22: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

3Working with complex data

In this chapter, we present query examples that use complex data types (arrays,maps, records). To follow along with the examples, get the Examples download from here and run the SQLAdvancedExamples script found in the sql folder. This scriptcreates the table and imports the data used.

SQLAdvancedExamples ScriptThe SQLAdvancedExamples script creates the following table:

CREATE TABLE Persons ( id integer, firstname string, lastname string, age integer, income integer, lastLogin timestamp(4), address record(street string, city string, state string, phones array(record(type enum(work, home), areacode integer, number integer ) ) ), connections array(integer), expenses map(integer), primary key (id));

The script also imports the following table rows:

{ "id":1, "firstname":"David", "lastname":"Morrison", "age":25, "income":100000, "lastLogin" : "2016-10-29T18:43:59.8319", "address":{"street":"150 Route 2", "city":"Antioch", "state":"TN", "zipcode" : 37013, "phones":[{"type":"home", "areacode":423, "number":8634379}]

3-1

Page 23: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

}, "connections":[2, 3], "expenses":{"food":1000, "gas":180}}

{ "id":2, "firstname":"John", "lastname":"Anderson", "age":35, "income":100000, "lastLogin" : "2016-11-28T13:01:11.2088", "address":{"street":"187 Hill Street", "city":"Beloit", "state":"WI", "zipcode" : 53511, "phones":[{"type":"home", "areacode":339, "number":1684972}] }, "connections":[1, 3], "expenses":{"books":100, "food":1700, "travel":2100}}

{ "id":3, "firstname":"John", "lastname":"Morgan", "age":38, "income":100000000, "lastLogin" : "2016-11-29T08:21:35.4971", "address":{"street":"187 Aspen Drive", "city":"Middleburg", "state":"FL", "phones":[{"type":"work", "areacode":305, "number":1234079}, {"type":"home", "areacode":305, "number":2066401} ] }, "connections":[1, 4, 2], "expenses":{"food":2000, "travel":700, "gas":10}}

{ "id":4, "firstname":"Peter", "lastname":"Smith", "age":38, "income":80000, "lastLogin" : "2016-10-19T09:18:05.5555", "address":{"street":"364 Mulberry Street", "city":"Leominster", "state":"MA", "phones":[{"type":"work", "areacode":339, "number":4120211},

Chapter 3SQLAdvancedExamples Script

3-2

Page 24: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

{"type":"work", "areacode":339, "number":8694021}, {"type":"home", "areacode":339, "number":1205678}, {"type":"home", "areacode":305, "number":8064321} ] }, "connections":[3, 5, 1, 2], "expenses":{"food":6000, "books":240, "clothes":2000, "shoes":1200}}

{ "id":5, "firstname":"Dana", "lastname":"Scully", "age":47, "income":400000, "lastLogin" : "2016-11-08T09:16:46.3929", "address":{"street":"427 Linden Avenue", "city":"Monroe Township", "state":"NJ", "phones":[{"type":"work", "areacode":201, "number":3213267}, {"type":"work", "areacode":201, "number":8765421}, {"type":"home", "areacode":339, "number":3414578} ] }, "connections":[2, 4, 1, 3], "expenses":{"food":900, "shoes":1000, "clothes":1500}}

You run the SQLAdvancedExamples script using the load command:

> cd <installdir>/examples/sql> java -jar <KVHOME>/lib/sql.jar -helper-hosts <host>:<port> \-store <storename> load \-file <KVHOME>/examples/sql/SQLAdvancedExamples.cli

Chapter 3SQLAdvancedExamples Script

3-3

Page 25: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Note:

The Persons table schema models people that can be connected to otherpeople in the table. All connections are stored in the "connections" column,which consists of an array of integers. Each integer is an ID of a person withwhom the subject is connected. The entries in the "connections" array aresorted in descending order, indicating the strength of the connection. Forexample, looking at the record for person 3, we see that John Morgan hasthese connections: [1, 4, 2]. The order of the array elements specifies thatJohn is most strongly connected with person 1, less connected with person4, and least connected with person 2.

Records in the Persons table also include an "expenses" column, declaredas an integer map. For each person, the map stores key-value pairs of stringitem types and integers representing money spent on the item. For example,one record has these expenses: {"food":900, "shoes":1000, "clothes":1500},other records have different items. One benefit of modelling expenses as amap type is to facilitate the categories being different for each person. Later,we may want to add or delete categories dynamically, without changing thetable schema, which maps readily support. An item to note about this map isthat it is an integer map always contains key-value pairs, and keys arealways strings.

Working with TimestampsTo specify a timestamp value in a query, provide it as a string, and cast it to aTimestamp data type. For example:

sql-> SELECT id, firstname, lastname FROM Persons WHERElastLogin = CAST("2016-10-19T09:18:05.5555" AS TIMESTAMP); +----+-----------+----------+ | id | firstname | lastname | +----+-----------+----------+ | 4 | Peter | Smith | +----+-----------+----------+

1 row returned

Timestamp queries often involve a range of time, which requires multiple casts:

sql-> SELECT id, firstname, lastname, lastLogin FROM Persons WHERE lastLogin > CAST("2016-11-01" AS TIMESTAMP) AND lastLogin < CAST("2016-11-30" AS TIMESTAMP); +----+-----------+----------+--------------------------+ | id | firstname | lastname | lastLogin | +----+-----------+----------+--------------------------+ | 3 | John | Morgan | 2016-11-29T08:21:35.4971 | | 2 | John | Anderson | 2016-11-28T13:01:11.2088 | | 5 | Dana | Scully | 2016-11-08T09:16:46.3929 | +----+-----------+----------+--------------------------+

Chapter 3Working with Timestamps

3-4

Page 26: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

3 rows returned

You can also use various Timestamp functions to return specific time and date valuesfrom the Timestamp data. (See Timestamp Functions for a full list of these functions).For example:

sql-> SELECT id, firstname, lastname, year(lastLogin) AS Year, month(lastLogin) AS Month, day(lastLogin) AS Day, hour(lastLogin) AS Hour, minute(lastLogin) AS Minute FROM Persons; +----+-----------+----------+------+-------+-----+------+--------+ | id | firstname | lastname | Year | Month | Day | Hour | Minute | +----+-----------+----------+------+-------+-----+------+--------+ | 3 | John | Morgan | 2016 | 11 | 29 | 8 | 21 | | 2 | John | Anderson | 2016 | 11 | 28 | 13 | 1 | | 4 | Peter | Smith | 2016 | 10 | 19 | 9 | 18 | | 5 | Dana | Scully | 2016 | 11 | 8 | 9 | 16 | | 1 | David | Morrison | 2016 | 10 | 29 | 18 | 43 | +----+-----------+----------+------+-------+-----+------+--------+

Alternatively, use the EXTRACT function:

sql-> SELECT id, firstname, lastname, EXTRACT(YEAR FROM lastLogin) AS Year, EXTRACT(MONTH FROM lastLogin) AS Month, EXTRACT(DAY FROM lastLogin) AS Day, EXTRACT(HOUR FROM lastLogin) AS Hour, EXTRACT(MINUTE FROM lastLogin) AS Minute FROM Persons; +----+-----------+----------+------+-------+-----+------+--------+ | id | firstname | lastname | Year | Month | Day | Hour | Minute | +----+-----------+----------+------+-------+-----+------+--------+ | 3 | John | Morgan | 2016 | 11 | 29 | 8 | 21 | | 4 | Peter | Smith | 2016 | 10 | 19 | 9 | 18 | | 1 | David | Morrison | 2016 | 10 | 29 | 18 | 43 | | 2 | John | Anderson | 2016 | 11 | 28 | 13 | 1 | | 5 | Dana | Scully | 2016 | 11 | 8 | 9 | 16 | +----+-----------+----------+------+-------+-----+------+--------+

5 rows returnedsql->

Working With ArraysYou can use slice or filter steps to select elements out of an array. We start with someexamples using slice steps.

Chapter 3Working With Arrays

3-5

Page 27: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

To select and display the second connection of each person, we use this query:

sql-> SELECT lastname, connections[1]AS connection FROM Persons; +----------+------------+ | lastname | connection | +----------+------------+ | Scully | 2 | | Smith | 4 | | Morgan | 2 | | Anderson | 2 | | Morrison | 2 | +----------+------------+

5 rows returned

In the example, the slice step [1] is applied to the connections array. Since arrayelements start with 0, 1 selects the second connection value.

You can also use a slice step to select all array elements whose positions are within arange: [low:high], where low and high are expressions to specify the range boundaries.You can omit low and high expressions if you do not require a low or high boundary.

For example, the following query returns the lastname and the first 3 connections ofperson 5 as strongconnections:

sql-> SELECT lastname, [connections[0:2]]AS strongconnections FROM Persons WHERE id = 5; +----------+-------------------+ | lastname | strongconnections | +----------+-------------------+ | Scully | 2 | | | 4 | | | 1 | +----------+-------------------+

1 row returned

In the above query for Person 5, the path expression connections[0:2] returns theperson's first 3 connections. Here, the range is [0:2], so 0 is the low expression and 2is the high. The path expression returns its result as a list of 3 items. The list isconverted to an array (a single item) by enclosing the path expression in an array-constructor expression ([]). The array constructor creates a new array containing thethree connections. Notice that although the query shell displays the elements of thisconstructed array vertically, the number of rows returned by this query is 1.

Use of the array constructor in the select clause is optional. If no array constructor isused, an array will still be constructed, but only if the select-clause expression doesindeed return more than one item. If exactly one item is returned, the result will containjust that one item. If the expression returns nothing (an empty result), NULL is used asthe result. This behavior is illustrated in the next example, which we will run with andwithout an array constructor.

As mentioned above, you can omit the low or high expression when specifying therange for a slice step. For example the following query specifies a range of [3:] which

Chapter 3Working With Arrays

3-6

Page 28: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

returns all connections after the third one. Notice that for persons having only 3connections or less, an empty array is constructed and returned due to the use of thearray constructor.

To fully illustrate this behavior, we display this output in mode JSON because theCOLUMN mode does not differentiate between a single item and an array containing asingle item.

sql-> mode JSONQuery output mode is JSONsql-> SELECT id, [connections[3:]] AS weakConnections FROM Persons;{"id":3,"weakConnections":[]}{"id":4,"weakConnections":[2]}{"id":2,"weakConnections":[]}{"id":5,"weakConnections":[3]}{"id":1,"weakConnections":[]}

5 rows returned

Now we run the same query, but without the array constructor. Notice how single itemsare not contained in an array, and for rows with no match, NULL is returned instead ofan empty array.

sql-> SELECT id, connections[3:] AS weakConnections FROM Persons;{"id":2,"weakConnections":null}{"id":3,"weakConnections":null}{"id":4,"weakConnections":2}{"id":5,"weakConnections":3}{"id":1,"weakConnections":null}

5 rows returnedsql-> mode COLUMNQuery output mode is COLUMNsql->

As a last example of slice steps, the following query returns the last 3 connections ofeach person. In this query, the slice step is [size($)-3:]. In this expression, the $ isan implicitly declared variable that references the array that the slice step is applied to.In this example, $ references the connections array. The size() built-in function returnsthe size (number of elements) of the input array. So, in this example, size($) is the sizeof the current connections array. Finally, size($)-3 computes the third position from theend of the current connections array.

sql-> SELECT id, [connections[size($)-3:]]AS weakConnections FROM Persons; +----+-------------------+ | id | weakConnections | +----+-------------------+ | 5 | 4 | | | 1 | | | 3 | +----+-------------------+ | 4 | 5 | | | 1 |

Chapter 3Working With Arrays

3-7

Page 29: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| | 2 | +----+-------------------+ | 3 | 1 | | | 4 | | | 2 | +----+-------------------+ | 2 | 1 | | | 3 | +----+-------------------+ | 1 | 2 | | | 3 | +----+-------------------+

5 rows returned

We now turn our attention to filter steps on arrays. Like slice steps, filter steps also usethe square brackets ([]) syntax. However, what goes inside the [] is different. With filtersteps there is either nothing inside the [] or a single expression that acts as a condition(returns a boolean result). In the former case, all the elements of the array areselected (the array is "unnested"). In the latter case, the condition is applied to eachelement in turn, and if the result is true, the element is selected, otherwise it isskipped. For example:

The following query returns the id and connections of persons who are connected toperson 4:

sql-> SELECT id, connectionsFROM Persons p WHERE p.connections[] =any 4; +----+-------------+ | id | connections | +----+-------------+ | 3 | 1 | | | 4 | | | 2 | +----+-------------+ | 5 | 2 | | | 4 | | | 1 | | | 3 | +----+-------------+

2 rows returned

In the above query, the expression p.connections[] returns all the connections of aperson. Then, the =any operator returns true if this sequence of connections containsthe number 4. Sequence operators are described in Sequence Comparison Operators.

The following query returns the id and connections of persons who are connected withany person having an id greater than 4:

sql-> SELECT id, connections FROM Persons pWHERE p.connections[] >any 4; +----+-------------+ | id | connections |

Chapter 3Working With Arrays

3-8

Page 30: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

+----+-------------+ | 4 | 3 | | | 5 | | | 1 | | | 2 | +----+-------------+

1 row returned

The following query returns, for each person, the person's last name and the phonenumbers with area code 339:

sql-> SELECT lastname,[ p.address.phones[$element.areacode = 339].number ]AS phoneNumbers FROM Persons p; +----------+--------------+ | lastname | phoneNumbers | +----------+--------------+ | Scully | 3414578 | +----------+--------------+ | Smith | 4120211 | | | 8694021 | | | 1205678 | +----------+--------------+ | Morgan | | +----------+--------------+ | Anderson | 1684972 | +----------+--------------+ | Morrison | | +----------+--------------+

5 rows returned

In the above query, the filter step [$element.areacode = 339] is applied to thephones array of each person. The filter step evaluates thecondition $element.areacode = 339 on each element of the array. This conditionexpression uses the implicitly declared variable $element, which references thecurrent element of the array. An empty array is returned for persons that do not haveany phone number in the 339 area code. If we wanted to filter out such persons fromthe result, we would write the following query:

sql-> SELECT lastname,[ p.address.phones[$element.areacode = 339].number ]AS phoneNumbers FROM Persons p WHERE p.address.phones.areacode =any 339; +----------+--------------+ | lastname | phoneNumbers | +----------+--------------+ | Scully | 3414578 | +----------+--------------+ | Smith | 4120211 | | | 8694021 | | | 1205678 | +----------+--------------+ | Anderson | 1684972 |

Chapter 3Working With Arrays

3-9

Page 31: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

+----------+--------------+

3 rows returned

The previous query contains the path expression p.address.phones.areacode. In thatexpression, the field step .areacode is applied to an array field (phones). In this case,the field step is applied to each element of the array in turn. In fact, the pathexpression is equivalent to p.address.phones[].areacode.

In addition to the implicitly-declared $ and $element variables, the condition inside afilter step can also use the $pos variable (also implicitly declared). $pos references theposition within the array of the current element (the element on which the condition isapplied). For example, the following query selects the "interesting" connections of eachperson, where a connection is considered interesting if it is among the 3 strongestconnections and connects to a person with an id greater or equal to 4.

sql-> SELECT id, [p.connections[$element >= 4 and $pos < 3]]AS interestingConnections FROM Persons p; +----+------------------------+ | id | interestingConnections | +----+------------------------+ | 5 | 4 | +----+------------------------+ | 4 | 5 | +----+------------------------+ | 3 | 4 | +----+------------------------+ | 2 | | +----+------------------------+ | 1 | | +----+------------------------+

5 rows returned

Finally, two arrays can be compared with each other using the usual comparisonoperators (=, !=, >, >=, >, and >=). For example the following query constructs thearray [1,3] and selects persons whose connections array is equal to [1,3].

sql-> SELECT lastname FROM Persons pWHERE p.connections = [1,3]; +----------+ | lastname | +----------+ | Anderson | +----------+

1 row returned

Chapter 3Working With Arrays

3-10

Page 32: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Working with RecordsYou can use a field step to select the value of a field from a record. For example, toreturn the id, last name, and city of persons who reside in Florida:

sql-> SELECT id, lastname, p.address.cityFROM Persons p WHERE p.address.state = "FL"; +----+----------+------------+ | id | lastname | city | +----+----------+------------+ | 3 | Morgan | Middleburg | +----+----------+------------+

1 row returned

In the above query, the path expression (see Path Expressions) p.address.stateconsists of 2 field steps: .address selects the address field of the current row (rowscan be viewed as records, whose fields are the row columns), and .state selects thestate field of the current address.

The example record contains an array of phone numbers. You can form queriesagainst that array using a combination of path steps and sequence comparisonoperators (see Sequence Comparison Operators). For example, to return the lastname of persons who have a phone number with area code 423:

sql-> SELECT lastname FROM Personsp WHERE p.address.phones.areacode =any 423; +----------+ | lastname | +----------+ | Morrison | +----------+

1 row returned

In the above query, the path expression p.address.phones.areacode returns all thearea codes of a person. Then, the =any operator returns true if this sequence of areacodes contains the number 423. Notice also that the field step .areacode is applied toan array field (phones). This is allowed if the array contains records or maps. In thiscase, the field step is applied to each element of the array in turn.

The following example returns all the persons who had three connections. Notice theuse of [] after connections: it is an array filter step, which returns all the elements of theconnections array as a sequence (it is unnesting the array).

sql-> SELECT id, firstName, lastName, connections from Persons where connections[] =any 3 ORDER BY id; +----+-----------+----------+-------------+ | id | firstName | lastName | connections | +----+-----------+----------+-------------+ | 1 | David | Morrison | 2 | | | | | 3 |

Chapter 3Working with Records

3-11

Page 33: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

+----+-----------+----------+-------------+ | 2 | John | Anderson | 1 | | | | | 3 | +----+-----------+----------+-------------+ | 4 | Peter | Smith | 3 | | | | | 5 | | | | | 1 | | | | | 2 | +----+-----------+----------+-------------+ | 5 | Dana | Scully | 2 | | | | | 4 | | | | | 1 | | | | | 3 | +----+-----------+----------+-------------+

4 rows returned

This query can use ORDER BY to sort the results because the sort is being performedon the table's primary key. The next section shows sorting on non-primary key fieldsthrough the use of indexes.

See Working With Arrays for more examples of querying against data contained inarrays.

Using ORDER BY to Sort ResultsTo sort the results from a SELECT statement using a field that is not the table'sprimary key, you must first create an index for the column of choice. For example, forthe next table, to query based on a Timestamp and sort the results in descendingorder by the timestamp, create an index:

sql-> SELECT id, firstname, lastname, lastLogin FROM Persons; +----+-----------+----------+--------------------------+ | id | firstname | lastname | lastLogin | +----+-----------+----------+--------------------------+ | 3 | John | Morgan | 2016-11-29T08:21:35.4971 | | 4 | Peter | Smith | 2016-10-19T09:18:05.5555 | | 2 | John | Anderson | 2016-11-28T13:01:11.2088 | | 5 | Dana | Scully | 2016-11-08T09:16:46.3929 | | 1 | David | Morrison | 2016-10-29T18:43:59.8319 | +----+-----------+----------+--------------------------+

5 rows returnedsql-> CREATE INDEX tsidx1 on Persons (lastLogin);Statement completed successfullysql-> SELECT id, firstname, lastname, lastLogin FROM Persons ORDER BY lastLogin DESC; +----+-----------+----------+--------------------------+ | id | firstname | lastname | lastLogin | +----+-----------+----------+--------------------------+ | 3 | John | Morgan | 2016-11-29T08:21:35.4971 | | 2 | John | Anderson | 2016-11-28T13:01:11.2088 | | 5 | Dana | Scully | 2016-11-08T09:16:46.3929 | | 1 | David | Morrison | 2016-10-29T18:43:59.8319 |

Chapter 3Using ORDER BY to Sort Results

3-12

Page 34: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| 4 | Peter | Smith | 2016-10-19T09:18:05.5555 | +----+-----------+----------+--------------------------+

5 rows returned

SQL for Oracle NoSQL Database can also sort query results by the values of nestedrecords. To do so, create an index of the nested field (or fields). For example, you cancreate an index of address.state from the Persons table, and then order by state:

sql-> CREATE INDEX indx1 on Persons (address.state);Statement completed successfullysql-> SELECT id, $p.address.state FROMPersons $p ORDER BY $p.address.state; +----+-------+ | id | state | +----+-------+ | 3 | FL | | 4 | MA | | 5 | NJ | | 1 | TN | | 2 | WI | +----+-------+

5 rows returned

To learn more about indexes see Working With Indexes.

Working With MapsThe path steps applicable to maps are field and filter steps. Slice steps do not makesense for maps, because maps are unordered, and as a result, their entries do nothave any fixed positions.

You can use a field step to select the value of a field from a map. For example, toreturn the lastname and the food expenses of all persons:

sql-> SELECT lastname, p.expenses.foodFROM Persons p; +----------+------+ | lastname | food | +----------+------+ | Morgan | 2000 | | Morrison | 1000 | | Scully | 900 | | Smith | 6000 | | Anderson | 1700 | +----------+------+

5 rows returned

In the above query, the path expression p.expenses.food consists of 2 fieldsteps: .expenses selects the expenses field of the current row and .food selects thevalue of the food field/entry from the current expenses map.

Chapter 3Working With Maps

3-13

Page 35: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

To return the lastname and amount spent on travel for each person who spent lessthan $3000 on food:

sql-> SELECT lastname, p.expenses.travelFROM Persons p WHERE p.expenses.food < 3000; +----------+--------+ | lastname | travel | +----------+--------+ | Scully | NULL | | Morgan | 700 | | Anderson | 2100 | | Morrison | NULL | +----------+--------+

4 rows returned

Notice that NULL is returned for persons who did not have any travel expenses.

Filter steps are performed using either the .values() or .keys() path steps. To selectvalues of map entries, use .values(<cond>). To select keys of map entries,use .keys(<cond>). If no condition is used in these steps, all the values or keys of theinput map are selected. If the steps do contain a condition expression, the condition isevaluated for each entry, and the value or key of the entry is selected/skipped if theresult is true/false.

The implicitly-declared variables $key and $value can be used inside a map filtercondition. $key references the key of the current entry and $value references theassociated value. Notice that, contrary to arrays, the $pos variable can not be be usedinside map filters (because map entries do not have fixed positions).

To show, for each user, their id and the expense categories where they spent morethan $1000:

sql-> SELECT id, p.expenses.keys($value > 1000) as Expenses from Persons p; +----+---------------------+ | id | Expenses | +----+---------------------+ | 4 | clothes | | | food | | | shoes | +----+---------------------+ | 3 | food | +----+---------------------+ | 2 | food | | | travel | +----+---------------------+ | 5 | clothes | +----+---------------------+ | 1 | NULL | +----+---------------------+

To return the id and the expense categories in which the user spent more than theyspent on clothes, use the following filter step expression. In this query, the context-

Chapter 3Working With Maps

3-14

Page 36: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

item variable ($) appearing in the filter step expression [$value > $.clothes] refers tothe expenses map as a whole.

sql-> SELECT id, p.expenses.keys($value > $.clothes) FROM Persons p; +----+---------------------+ | id | Column_2 | +----+---------------------+ | 3 | NULL | +----+---------------------+ | 2 | NULL | +----+---------------------+ | 5 | NULL | +----+---------------------+ | 1 | NULL | +----+---------------------+ | 4 | food | +----+---------------------+

To return the id and expenses data of any person who spent more on any categorythan what they spent on food:

sql-> SELECT id, p.expensesFROM Persons pWHERE p.expenses.values() >any p.expenses.food; +----+---------------------+ | id | expenses | +----+---------------------+ | 5 | clothes | 1500 | | | food | 900 | | | shoes | 1000 | +----+---------------------+ | 2 | books | 100 | | | food | 1700 | | | travel | 2100 | +----+---------------------+

2 rows returned

To return the id of all persons who consumed more than $2000 in any category otherthan food:

sql-> SELECT id FROM Persons pWHERE p.expenses.values($key != "food") >any 2000; +----+ | id | +----+ | 2 | +----+

1 row returned

Chapter 3Working With Maps

3-15

Page 37: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Using the size() FunctionThe size function can be used to return the size (number of fields/entries) of a complexitem (record, array, or map). For example:

To return the id and the number of phones that each person has:

sql-> SELECT id, size(p.address.phones)AS registeredphones FROM Persons p; +----+------------------+ | id | registeredphones | +----+------------------+ | 5 | 3 | | 3 | 2 | | 4 | 4 | | 2 | 1 | | 1 | 1 | +----+------------------+

5 rows returned

To return the id and the number of expenses categories for each person: has:

sql-> SELECT id, size(p.expenses) AScategories FROM Persons p; +----+------------+ | id | categories | +----+------------+ | 4 | 4 | | 3 | 3 | | 2 | 3 | | 1 | 2 | | 5 | 3 | +----+------------+

5 rows returned

To return for each person their id and the number of expenses categories for which theexpenses were more than 2000:

sql-> SELECT id, size([p.expenses.values($value > 2000)]) AS expensiveCategories FROM Persons p; +----+---------------------+ | id | expensiveCategories | +----+---------------------+ | 3 | 0 | | 2 | 1 | | 5 | 0 | | 1 | 0 | | 4 | 1 | +----+---------------------+

Chapter 3Using the size() Function

3-16

Page 38: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

5 rows returned

Chapter 3Using the size() Function

3-17

Page 39: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

4Working with JSON

This chapter provides examples on working with JSON data. If you want to followalong with the examples, get the Examples download from here and run theSQLJSONExamples script found in the sqlfolder. This creates the table and imports thedata used.

JSON data is written to JSON data columns by providing a JSON object. This objectcan contain any valid JSON data. The input data is parsed and stored internally asOracle NoSQL Database datatypes:

• When numbers are encountered, they are converted to integer, long, or doubleitems, depending on the actual value of the number (float items are not used forJSON).

• Strings in the input text are mapped to string items.

• Boolean values are mapped to boolean items.

• JSON nulls are mapped to JSON null items.

• When an array is encountered in the input text, an array item is created whosetype is Array(JSON). This is done unconditionally, no matter what the actualcontents of the array might be.

• When a JSON object is encountered in the input text, a map item is created whosetype is Map(JSON), unconditionally.

Note:

There is no JSON equivalent to the TIMESTAMP datatype, so if input textcontains a string in the TIMESTAMP format it is simply stored as a stringitem in the JSON column.

The remainder of this chapter provides an overview to querying JSON data.

SQLJSONExamples ScriptThe SQLJSONExample is available to illustrate JSON usage. This script creates thefollowing table:

create table if not exists JSONPersons ( id integer, person JSON, primary key (id));

4-1

Page 40: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

The script imports the following table rows. Notice that the content for the personcolumn, which is of type JSON contains a JSON object. That object contains a series offields which represent our person. We have deliberately included inconsistentinformation in this example so as to illustrate how to handle various queries whenworking with JSON data.

{ "id":1, "person" : { "firstname":"David", "lastname":"Morrison", "age":25, "income":100000, "lastLogin" : "2016-10-29T18:43:59.8319", "address":{"street":"150 Route 2", "city":"Antioch", "state":"TN", "zipcode" : 37013, "phones":[{"type":"home", "areacode":423, "number":8634379}] }, "connections":[2, 3], "expenses":{"food":1000, "gas":180} }}

{ "id":2, "person" : { "firstname":"John", "lastname":"Anderson", "age":35, "income":100000, "lastLogin" : "2016-11-28T13:01:11.2088", "address":{"street":"187 Hill Street", "city":"Beloit", "state":"WI", "zipcode" : 53511, "phones":[{"type":"home", "areacode":339, "number":1684972}] }, "connections":[1, 3], "expenses":{"books":100, "food":1700, "travel":2100} }}

{ "id":3, "person" : { "firstname":"John", "lastname":"Morgan", "age":38, "income":100000000, "lastLogin" : "2016-11-29T08:21:35.4971", "address":{"street":"187 Aspen Drive",

Chapter 4SQLJSONExamples Script

4-2

Page 41: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

"city":"Middleburg", "state":"FL", "phones":[{"type":"work", "areacode":305, "number":1234079}, {"type":"home", "areacode":305, "number":2066401} ] }, "connections":[1, 4, 2], "expenses":{"food":2000, "travel":700, "gas":10} }}{ "id":4, "person": { "firstname":"Peter", "lastname":"Smith", "age":38, "income":80000, "lastLogin" : "2016-10-19T09:18:05.5555", "address":{"street":"364 Mulberry Street", "city":"Leominster", "state":"MA", "phones":[{"type":"work", "areacode":339, "number":4120211}, {"type":"work", "areacode":339, "number":8694021}, {"type":"home", "areacode":339, "number":1205678}, null, {"type":"home", "areacode":305, "number":8064321} ] }, "connections":[3, 5, 1, 2], "expenses":{"food":6000, "books":240, "clothes":2000, "shoes":1200} }}

{ "id":5, "person" : { "firstname":"Dana", "lastname":"Scully", "age":47, "income":400000, "lastLogin" : "2016-11-08T09:16:46.3929", "address":{"street":"427 Linden Avenue", "city":"Monroe Township", "state":"NJ", "phones":[{"type":"work", "areacode":201, "number":3213267}, {"type":"work", "areacode":201, "number":8765421},

Chapter 4SQLJSONExamples Script

4-3

Page 42: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

{"type":"home", "areacode":339, "number":3414578} ] }, "connections":[2, 4, 1, 3], "expenses":{"food":900, "shoes":1000, "clothes":1500} }}

{ "id":6, "person" : { "mynumber":5, "myarray":[1,2,3,4] }}

{ "id":7, "person" : { "mynumber":"5", "myarray":["1","2","3","4"] }}

You run the SQLJSONExamples script using the load command:

> cd <installdir>/examples/sql> java -jar <KVHOME>/lib/sql.jar -helper-hosts <host>:<port> \-store <storename> load \-file <KVHOME>/examples/sql/SQLJSONExamples.cli

Basic QueriesBecause JSON is parsed and stored internally in native data formats with OracleNoSQL Database, querying JSON data is no different than querying data in othercolumn types. See Simple SELECT Queries and Working with complex data forintroductory examples of how to form these queries.

In our JSONPersons example, all of the data for each person is contained in a columnof type JSON called person. This data is presented as a JSON object, and mappedinternally into a Map(JSON) type. You can query information in this column as youwould query a Map of any other type. For example:

sql-> SELECT id, j.person.lastname, j.person.age FROM JSONPersons j; +----+---------------------+------------+ | id | lastname | age | +----+---------------------+------------+ | 3 | Morgan | 38 | +----+---------------------+------------+ | 2 | Anderson | 35 | +----+---------------------+------------+

Chapter 4Basic Queries

4-4

Page 43: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| 5 | Scully | 47 | +----+---------------------+------------+ | 1 | Morrison | 25 | +----+---------------------+------------+ | 4 | Smith | 38 | +----+---------------------+------------+ | 6 | NULL | NULL | +----+---------------------+------------+ | 7 | NULL | NULL | +----+---------------------+------------+

7 rows returned

The last two rows in returned from this query contain all NULLs. This is because thoserows were populated using JSON objects that are different than the objects used topopulate the rest of the table. This capability of JSON is both a strength and aweakness. As a plus, you can modify your schema easily. However, if you are notcareful, you can end up with tables containing dissimilar data in both large and smallways.

Because the JSON object is stored as a map, you can use normal map step functionson the column. For example:

sql-> SELECT id, j.person.expenses.keys($value > 1000) as Expenses from JSONPersons j;+----+---------------------+ | id | Expenses | +----+---------------------+ | 3 | food | +----+---------------------+ | 2 | food | | | travel | +----+---------------------+ | 4 | clothes | | | food | | | shoes | +----+---------------------+ | 6 | NULL | +----+---------------------+ | 5 | clothes | +----+---------------------+ | 7 | NULL | +----+---------------------+ | 1 | NULL | +----+---------------------+

7 rows returned

Here, id 1 is NULL because that user had no expenses greater than $1000, while id 6and 7 are NULL because they have no j.person.expenses field.

Chapter 4Basic Queries

4-5

Page 44: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Using WHERE EXISTS with JSONAs we saw in the previous section, different rows in the same table can have dissimilarinformation in them when a column type is JSON. To identify whether desiredinformation exists for a given JSON column, use the EXISTS operator.

For example, some of the JSON persons have a zip code entered for their address,and others do not. Use this query to see all the users with a zipcode:

sql-> SELECT id, j.person.address AS Address FROM JSONPersons j WHERE EXISTS j.person.address.zipcode; +----+--------------------------------+ | id | Address | +----+--------------------------------+ | 2 | city | Beloit | | | phones | | | areacode | 339 | | | number | 1684972 | | | type | home | | | state | WI | | | street | 187 Hill Street | | | zipcode | 53511 | +----+--------------------------------+ | 1 | city | Antioch | | | phones | | | areacode | 423 | | | number | 8634379 | | | type | home | | | state | TN | | | street | 150 Route 2 | | | zipcode | 37013 | +----+--------------------------------+

2 rows returned

When querying data for inconsistencies, it is often more useful to see all rows whereinformation is missing by using WHERE NOT EXISTS:

sql-> SELECT * FROM JSONPersons j WHERE NOT EXISTS j.person.lastname; +----+-------------------+ | id | person | +----+-------------------+ | 7 | myarray | | | 1 | | | 2 | | | 3 | | | 4 | | | mynumber | 5 | +----+-------------------+ | 6 | myarray | | | 1 | | | 2 | | | 3 |

Chapter 4Using WHERE EXISTS with JSON

4-6

Page 45: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| | 4 | | | mynumber | 5 | +----+-------------------+

1 row returned

Seeking NULLS in ArraysAll arrays found in a JSON input stream are stored internally as ARRAY(JSON). Thismeans that it is possible for the array to have inconsistent types for its members.

In our example, the phones array for user id 4 contains a null element:

sql-> SELECT j.person.address.phones FROM JSONPersons j WHERE j.id=4; +--------------------+ | phones | +--------------------+ | areacode | 339 | | number | 4120211 | | type | work | | | | areacode | 339 | | number | 8694021 | | type | work | | | | areacode | 339 | | number | 1205678 | | type | home | | null | | | | areacode | 305 | | number | 8064321 | | type | home | +--------------------+

A way to discover this in your table is to examine the phones array for null values:

sql-> SELECT id, j.person.address.phones FROM JSONPersons j WHERE j.person.address.phones[] =any null; +----+--------------------+ | id | phones | +----+--------------------+ | 4 | areacode | 339 | | | number | 4120211 | | | type | work | | | | | | areacode | 339 | | | number | 8694021 | | | type | work | | | | | | areacode | 339 | | | number | 1205678 |

Chapter 4Seeking NULLS in Arrays

4-7

Page 46: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| | type | home | | | null | | | | | | areacode | 305 | | | number | 8064321 | | | type | home | +----+--------------------+

1 row returned

Notice the use of the array filter step ([]) in the previous query. This is needed tounpack the array into a sequence so that the =any comparison operator can be usedwith it.

Examining Data Types JSON ColumnsThe example data contains a couple of rows with unusual data:

{ "id":6, "person" : { "mynumber":5, "myarray":[1,2,3,4] }}

{ "id":7, "person" : { "mynumber":"5", "myarray":["1","2","3","4"] }}

You can locate them using the query:

sql-> SELECT * FROM JSONPersons j WHERE EXISTS j.person.mynumber; +----+-------------------+ | id | person | +----+-------------------+ | 6 | myarray | | | 1 | | | 2 | | | 3 | | | 4 | | | mynumber | 5 | +----+-------------------+ | 7 | myarray | | | 1 | | | 2 | | | 3 | | | 4 | | | mynumber | 5 |

Chapter 4Examining Data Types JSON Columns

4-8

Page 47: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

+----+-------------------+

2 rows returned

However, notice that these two rows actually contain numbers stored as differenttypes. ID 6 stores integers while ID 7 stores strings. You can select a row based on itstype:

sql-> SELECT * FROM JSONPersons j WHERE j.person.mynumber IS OF TYPE (integer); +----+-------------------+ | id | person | +----+-------------------+ | 6 | myarray | | | 1 | | | 2 | | | 3 | | | 4 | | | mynumber | 5 | +----+-------------------+

Notice that if you use IS NOT OF TYPE then every row in the table is returned except id6. This is because for all the other rows, j.person.mynumber evaluates to jnull, whichis not an integer.

sql-> SELECT id FROM JSONPersons j WHERE j.person.mynumber IS NOT OF TYPE (integer); +----+ | id | +----+ | 3 | | 2 | | 5 | | 4 | | 1 | | 7 | +----+

6 rows returned

To solve this problem, also check for the existence of j.person.mynumber:

sql-> SELECT id from JSONPersons j WHERE EXISTS j.person.mynumber and j.person.mynumber IS NOT OF TYPE (integer); +----+ | id | +----+ | 7 | +----+

1 row returned

Chapter 4Examining Data Types JSON Columns

4-9

Page 48: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

You can also perform type checking based on the type of data contained in the array.Recall that our rows contain arrays with integers and arrays with strings. You canreturn the row with just the array of strings using:

sql-> SELECT id, j.person.myarray FROM JSONPersons j WHERE j.person.myarray[] IS OF TYPE (string+); +----+-------------------+ | id | myarray | +----+-------------------+ | 7 | 1 | | | 2 | | | 3 | | | 4 | +----+-------------------+

1 row returned

Here, we use the array filter step ([]) in the WHERE clause to unpack the array into asequence. This allows is-of-type to iterate over the sequence, checking the type ofeach element. If every element in the sequence matches the identified type (string, inthis case), then the is-of-type returns true.

Also notice that the query uses the + cardinality modifier. This means that is-of-typewill return true only if the input sequence (myarray[], in this case) contains ONE ORMORE elements that match the identified type (string). If we used *, then 0 or moreelements would have to match the identified type in order for true to return. Becauseour table contains a mix of rows with different schema, the result is that every rowexcept id 6 is returned:

sql-> SELECT id, j.person.myarray FROM JSONPersons j WHERE j.person.myarray[] IS OF TYPE (string*); +----+-------------------+ | id | myarray | +----+-------------------+ | 3 | NULL | +----+-------------------+ | 5 | NULL | +----+-------------------+ | 1 | NULL | +----+-------------------+ | 7 | 1 | | | 2 | | | 3 | | | 4 | +----+-------------------+ | 4 | NULL | +----+-------------------+ | 2 | NULL | +----+-------------------+

6 rows returned

Chapter 4Examining Data Types JSON Columns

4-10

Page 49: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Finally, if we do not provide a cardinality modifier at all, then is-of-type returns true ifONE AND ONLY one member of the input sequence matches the identified type. Inthis example, the result is that no rows are returned.

sql-> SELECT id, j.person.myarray FROM JSONPersons j WHERE j.person.myarray[] IS OF TYPE (string);

0 row returned

Using Map Steps with JSON DataOn import, Oracle NoSQL Database stores JSON objects as MAP(JSON). This meansyou can use map filter steps with your JSON objects.

For example, if you want to visually examine the JSON fields in use by your rows:

sql-> SELECT id, j.person.keys() FROM JSONPersons j; +----+------------------------+ | id | Column_2 | +----+------------------------+ | 4 | address | | | age | | | connections | | | expenses | | | firstname | | | income | | | lastLogin | | | lastname | +----+------------------------+ | 6 | myarray | | | mynumber | +----+------------------------+ | 3 | address | | | age | | | connections | | | expenses | | | firstname | | | income | | | lastLogin | | | lastname | +----+------------------------+ | 5 | address | | | age | | | connections | | | expenses | | | firstname | | | income | | | lastLogin | | | lastname | +----+------------------------+ | 1 | address | | | age | | | connections | | | expenses |

Chapter 4Using Map Steps with JSON Data

4-11

Page 50: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| | firstname | | | income | | | lastLogin | | | lastname | +----+------------------------+ | 7 | myarray | | | mynumber | +----+------------------------+ | 2 | address | | | age | | | connections | | | expenses | | | firstname | | | income | | | lastLogin | | | lastname | +----+------------------------+

7 rows returned

Casting DatatypesYou can cast one data type to another using the cast expression. See CastExpressions for rules about supported data type casting.

In JSON, casting is particularly useful for timestamp information because JSON hasno equivalent to the Oracle NoSQL Database Timestamp data type. Instead, thetimestamp information is carried in a JSON object as a string. To work with it as aTimestamp, use cast.

In Working with Timestamps we showed how to work with the timestamp data type. Inthis case, what you do is no different except you must cast both sides of theexpression. Also, because the left side of the expression is a sequence, you mustspecify a type quantifier (* in this case):

sql-> SELECT id, j.person.firstname, j.person.lastname, j.person.lastLogin FROM JSONPersons j WHERE CAST(j.person.lastLogin AS TIMESTAMP*) > CAST("2016-11-01" AS TIMESTAMP) AND CAST(j.person.lastLogin AS TIMESTAMP*) < CAST("2016-11-30" AS TIMESTAMP); +----+------------+--------------+----------------------------+ | id | firstname | lastname | lastLogin | +----+------------+--------------+----------------------------+ | 3 | John | Morgan | 2016-11-29T08:21:35.4971 | +----+------------+--------------+----------------------------+ | 2 | John | Anderson | 2016-11-28T13:01:11.2088 | +----+------------+--------------+----------------------------+ | 5 | Dana | Scully | 2016-11-08T09:16:46.3929 | +----+------------+--------------+----------------------------+

3 rows returned

Chapter 4Casting Datatypes

4-12

Page 51: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

As another example, you can cast to an integer and then operate on that number:

sql-> SELECT id, j.person.mynumber, CAST(j.person.mynumber as integer) * 10 AS TenTimes FROM JSONPersons j WHERE EXISTS j.person.mynumber; +----+---------------------+----------+ | id | mynumber | TenTimes | +----+---------------------+----------+ | 7 | 5 | 50 | +----+---------------------+----------+ | 6 | 5 | 50 | +----+---------------------+----------+

If you want to operate on just the row that contains the number as a string, use IS OFTYPE:

sql-> SELECT id, j.person.mynumber, CAST(j.person.mynumber as integer) * 10 AS TenTimes FROM JSONPersons j WHERE EXISTS j.person.mynumber AND j.person.mynumber IS OF TYPE (string); +----+---------------------+----------+ | id | mynumber | TenTimes | +----+---------------------+----------+ | 7 | 5 | 50 | +----+---------------------+----------+

Using Searched CaseA searched case expression can be helpful in identifying specific problems with theJSON data in your JSON columns. The example data we have been using in thischapter sometimes provides a JSONPersons.address field, and sometimes it doesnot. When an address is present, sometimes it provides a zipcode, and sometimes itdoes not. We can use a searched case expression to identify and describe the specificproblem with each row.

sql-> SELECT id, CASE WHEN NOT EXISTS j.person.address THEN j.person.keys() WHEN NOT EXISTS j.person.address.zipcode THEN "No Zipcode" ELSE j.person.address.zipcodeENDFROM JSONPersons j; +----+-----------------------+ | id | Column_2 | +----+-----------------------+ | 4 | No Zipcode | +----+-----------------------+ | 3 | No Zipcode | +----+-----------------------+ | 5 | No Zipcode | +----+-----------------------+

Chapter 4Using Searched Case

4-13

Page 52: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| 1 | 37013 | +----+-----------------------+ | 7 | myarray | | | mynumber | +----+-----------------------+ | 6 | myarray | | | mynumber | +----+-----------------------+ | 2 | 53511 | +----+-----------------------+

7 rows returned

We can improve the report by adding a third column that uses a second searchedcase expression:

sql-> SELECT id,CASE WHEN NOT EXISTS j.person.address THEN "No Address" WHEN NOT EXISTS j.person.address.zipcode THEN "No Zipcode" ELSE j.person.address.zipcodeEND,CASE WHEN NOT EXISTS j.person.address THEN j.person.keys() ELSE j.person.addressENDFROM JSONPersons j; +----+-----------------------+------------------------------------+ | id | Column_2 | Column_3 | +----+-----------------------+------------------------------------+ | 3 | No Zipcode | city | Middleburg | | | | phones | | | | areacode | 305 | | | | number | 1234079 | | | | type | work | | | | | | | | areacode | 305 | | | | number | 2066401 | | | | type | home | | | | state | FL | | | | street | 187 Aspen Drive | +----+-----------------------+------------------------------------+ | 2 | 53511 | city | Beloit | | | | phones | | | | areacode | 339 | | | | number | 1684972 | | | | type | home | | | | state | WI | | | | street | 187 Hill Street | | | | zipcode | 53511 | +----+-----------------------+------------------------------------+

Chapter 4Using Searched Case

4-14

Page 53: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| 5 | No Zipcode | city | Monroe Township | | | | phones | | | | areacode | 201 | | | | number | 3213267 | | | | type | work | | | | | | | | areacode | 201 | | | | number | 8765421 | | | | type | work | | | | | | | | areacode | 339 | | | | number | 3414578 | | | | type | home | | | | state | NJ | | | | street | 427 Linden Avenue | +----+-----------------------+------------------------------------+ | 1 | 37013 | city | Antioch | | | | phones | | | | areacode | 423 | | | | number | 8634379 | | | | type | home | | | | state | TN | | | | street | 150 Route 2 | | | | zipcode | 37013 | +----+-----------------------+------------------------------------+ | 7 | No Address | myarray | | | | mynumber | +----+-----------------------+------------------------------------+ | 4 | No Zipcode | city | Leominster | | | | phones | | | | areacode | 339 | | | | number | 4120211 | | | | type | work | | | | | | | | areacode | 339 | | | | number | 8694021 | | | | type | work | | | | | | | | areacode | 339 | | | | number | 1205678 | | | | type | home | | | | null | | | | | | | | areacode | 305 | | | | number | 8064321 | | | | type | home | | | | state | MA | | | | street | 364 Mulberry Street | +----+-----------------------+------------------------------------+ | 6 | No Address | myarray | | | | mynumber | +----+-----------------------+------------------------------------+

7 rows returned

Chapter 4Using Searched Case

4-15

Page 54: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Finally, it is possible to nest search case expressions. Our sample data also has aspurious null in the phones array (see id 4). We can report that in the following way(output is modified slightly to fit in the space allowed):

sql-> SELECT id,CASE WHEN EXISTS j.person.address THEN CASE WHEN EXISTS j.person.address.zipcode THEN CASE WHEN j.person.address.phones[] =any null THEN "Zipcode exists but null in the phones array" ELSE j.person.address.zipcode END WHEN j.person.address.phones[] =any null THEN "No zipcode and null in phones array" ELSE "No zipcode" END ELSE "No Address"END,CASE WHEN NOT EXISTS j.person.address THEN j.person.keys() ELSE j.person.addressEND FROM JSONPersons j; +----+------------------------+------------------------------------+ | id | Column_2 | Column_3 | +----+------------------------+------------------------------------+ | 3 | No zipcode | city | Middleburg | | | | phones | | | | areacode | 305 | | | | number | 1234079 | | | | type | work | | | | | | | | areacode | 305 | | | | number | 2066401 | | | | type | home | | | | state | FL | | | | street | 187 Aspen Drive | +----+------------------------+------------------------------------+ | 2 | 53511 | city | Beloit | | | | phones | | | | areacode | 339 | | | | number | 1684972 | | | | type | home | | | | state | WI | | | | street | 187 Hill Street | | | | zipcode | 53511 | +----+------------------------+------------------------------------+ | 5 | No zipcode | city | Monroe Township | | | | phones | | | | areacode | 201 |

Chapter 4Using Searched Case

4-16

Page 55: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| | | number | 3213267 | | | | type | work | | | | | | | | areacode | 201 | | | | number | 8765421 | | | | type | work | | | | | | | | areacode | 339 | | | | number | 3414578 | | | | type | home | | | | state | NJ | | | | street | 427 Linden Avenue | +----+------------------------+------------------------------------+ | 1 | 37013 | city | Antioch | | | | phones | | | | areacode | 423 | | | | number | 8634379 | | | | type | home | | | | state | TN | | | | street | 150 Route 2 | | | | zipcode | 37013 | +----+------------------------+------------------------------------+ | 7 | No Address | myarray | | | | mynumber | +----+------------------------+------------------------------------+ | 4 | No zipcode and null | city | Leominster | | | in phones array | phones | | | | areacode | 339 | | | | number | 4120211 | | | | type | work | | | | | | | | areacode | 339 | | | | number | 8694021 | | | | type | work | | | | | | | | areacode | 339 | | | | number | 1205678 | | | | type | home | | | | null | | | | | | | | areacode | 305 | | | | number | 8064321 | | | | type | home | | | | state | MA | | | | street | 364 Mulberry Street | +----+------------------------+------------------------------------+ | 6 | No Address | myarray | | | | mynumber | +----+------------------------+------------------------------------+

7 rows returned

Chapter 4Using Searched Case

4-17

Page 56: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

5Working With GeoJSON Data

The GeoJSON specification (https://tools.ietf.org/html/rfc7946) defines the structureand content of JSON objects representing geographical shapes on earth (calledgeometries). Oracle NoSQL Database implements several functions that interpretJSON geometry objects. The functions also let you search table rows containinggeometries that satisfy certain conditions. Search is made efficient through the use ofspecial indexes, as described in .

Note:

Support for GeoJson data is available only in the Oracle NoSQL DatabaseEnterprise Edition of Oracle NoSQL.

Geodetic CoordinatesAs described, all kinds of geometries are specified in terms of a set of positions.However, for line strings and polygons, the actual geometrical shape is formed by linesconnecting their positions. The GeoJSON specification defines a line between twopoints as the straight line that connects the points in the (flat) cartesian coordinatesystem, whose horizontal and vertical axes are the longitude and latitude, respectively.More precisely, the coordinates of every point on a line that does not cross theantimeridian between a point P1 = (lon1, lat1) and P2 = (lon2, lat2) can be calculatedas:

P = (lon, lat) = (lon1 + (lon2 - lon1) * t, lat1 + (lat2 - lat1) * t)

with t being a real number, greater than or equal to 0, and less than or equal to 1.

Unlike the GeoJSON specification, the Oracle NoSQL Database uses a geodeticcoordinate system, as defined in the World Geodetic System, WGS84, (https://gisgeography.com/wgs84-world-geodetic-system). A geodetic line between two pointsis the shortest line that can be drawn between the two points on the ellipsoidal surfaceof the earth.

5-1

Page 57: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

GeoJSON Data DefinitionsThe GeoJSON specification (https://tools.ietf.org/html/rfc7946) states that for a JSONobject to be a geometry, it requires two fields, type and coordinates. The value of thetype field specifies the kind of geometric shape the object describes. The value of thetype field must be one of the following strings, corresponding to different kinds ofgeometries:

• Point

• LineSegment

• Polygon

• MultiPoint

• MultiLineString

• MultiPolygon

• GeometryCollection

The coordinates value is an array with elements that define the geometrical shape.An exception to this is the GeometryCollection type, which is described below. Thecoordinates value depends on the geometric shape, but in all cases, specifies anumber of positions. A position defines a position on the surface of the earth as anarray of two double numbers, where the first number is the longitude and the secondnumber is the latitude. Longitude and latitude are specified as degrees and must rangebetween -180 – +180 and -90 – +90, respectively.

Note:

The GeoJSON specification allows a third coordinate for the altitude of theposition, but Oracle NoSQL Database does not support altitudes.

The kinds of geometries are defined as follows, each with an example of such anobject:

Chapter 5GeoJSON Data Definitions

5-2

Page 58: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Point — For type Point, the coordinates field is a single position:

{ "type" : "point", "coordinates" : [ 23.549, 35.2908 ] }

LineString — A LineString is one or more connected lines, with the end-point of oneline being the start-point of the next. The coordinates field is an array of two or morepositions. The first position is the start point of the first line, and each subsequentposition is the end point of the previous line and the start of the next line. Lines cancross each other.

{ "type" : "LineString","coordinates" : [ [-121.9447, 37.2975],[-121.9500, 37.3171],[-121.9892, 37.3182],[-122.1554, 37.3882],[-122.2899, 37.4589],[-122.4273, 37.6032],[-122.4304, 37.6267], [-122.3975, 37.6144]]}

Polygon — A polygon defines a surface area by specifying its outer perimeter and theperimeters of any potential holes inside the area. More precisely, a polygon consists ofone or more linear rings, where (a) a linear ring is a closed LineString with four ormore positions, (b) the first and last positions are equivalent, and they must containidentical values, (c) a linear ring is the boundary of a surface or the boundary of a holein a surface, and (d) a linear ring must follow the right-hand rule with respect to thearea it bounds. That is, positions for exterior rings must be ordered counterclockwise,and positions for holes must be ordered clockwise. Then, the coordinates field of apolygon must be an array of linear ring coordinate arrays, where the first must be theexterior ring, and any others must be interior rings.

The exterior ring bounds the surface, and the interior rings (if present) bound holeswithin the surface. The example below shows a polygon with no holes.

{ "type" : "polygon", "coordinates" : [ [[23.48, 35.16],[24.30, 35.16],[24.30, 35.50],[24.16, 35.61],[23.74, 35.70],[23.56, 35.60],[23.48, 35.16]]]}

Chapter 5GeoJSON Data Definitions

5-3

Page 59: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

MultiPoint — For type MultiPoint, the coordinates field is an array of two or morepositions:

{ "type" : "MultiPoint","coordinates" : [ [-121.9447, 37.2975],[-121.9500, 37.3171],[-122.3975, 37.6144]]}

MultiLineString — For type MultiLineString, the coordinates member is an array ofLineString coordinate arrays.

{ "type": "MultiLineString","coordinates": [ [ [100.0, 0.0], [01.0, 1.0] ],[ [102.0, 2.0], [103.0, 3.0] ]] }

MultiPolygon — For type MultiPolygon, the coordinates member is an array ofPolygon coordinate arrays.

{ "type": "MultiPolygon","coordinates": [[ [[102.0, 2.0],[103.0, 2.0], [103.0, 3.0], [102.0, 3.0], [102.0, 2.0] ] ], [ [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]] ] ] }

GeometryCollection — Instead of a coordinates field, a GeometryCollection has ageometries” field. The value of geometries is an array. Each element of this array is a

Chapter 5GeoJSON Data Definitions

5-4

Page 60: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

GeoJSON object whose kind is one of the six kinds defined above. In general, aGeometryCollection is a heterogeneous composition of smaller geometries.

{ "type": "GeometryCollection", "geometries": [{"type": "Point","coordinates": [100.0, 0.0]}, {"type": "LineString", "coordinates": [ [101.0, 0.0], [102.0, 1.0] ]} ] }

Note:

The GeoJSON specification defines two additional kinds of entities, Featureand FeatureCollection. The Oracle NoSQL Database does not support theseentities.

Searching GeoJSON DataThe Oracle NoSQL Database has the following functions to use for searchingGeoJSON data that has some relationship with a search geometry.

• boolean geo_intersect(any*, any*)

• boolean geo_inside(any*, any*)

• boolean geo_within_distance(any*, any*, double)

• boolean geo_near(any*, any*, double)

In addition to the search functions, two other functions are available, and listed as thelast two rows of the table:

Function Type Details

geo_intersect(any*, any*) boolean

Raises an error at compile time if the function can detect that anyoperand will not return a single valid GeoJson object. Otherwise,the runtime behavior is as follows:• Returns false if any operand returns 0 or more than 1 items.• Returns NULL if any operand returns NULL.• Returns false if any operand returns an item that is not a valid

GeoJson object.• Finally, if both operands return a single GeoJson object,

returns true if the two geometries have any points in common.Otherwise, returns false.

Chapter 5Searching GeoJSON Data

5-5

Page 61: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Function Type Details

geo_inside(any*, any*) boolean

Raises an error at compile time if the function can detect that anyoperand will not return a single valid GeoJson object. Otherwise,the runtime behavior is as follows:• Returns false if any operand returns 0 or more than 1 item.• Returns NULL if any operand returns NULL.• Returns false if any operand returns an item that is not a valid

GeoJson object.• Finally, if both operands return a single GeoJson object and

the second GeoJson is a polygon, the function returns true ifthe first geometry is completely contained inside the secondpolygon, with all of its points belonging to the interior of thepolygon. The interior of a polygon is all the points in thepolygon, except the points of the linear rings that define thepolygon’s boundary. Otherwise, returns false.

geo_within_distance(any*,any*, double)

boolean

Raises an error at compile time if the function detects that the firsttwo operands will not return a single valid GeoJson object.Otherwise, the runtime behavior is as follows:• Returns false if any of the first two operands returns 0 or more

than 1 item.• Returns NULL if any of the first two operands returns NULL.• Returns false if any of the first two operands returns an item

that is not a valid GeoJson object.• Finally, if both of the first two operands return a single

GeoJson object, the function returns true if the first geometryis within a distance of N meters from the second geometry,where N is the number returned by the third operand. Thedistance between 2 geometries is defined as the minimumamong the distances of any pair of points where the first pointbelongs to the first geometry, and the second point to thesecond geometry. Otherwise, returns false.

geo_near(any*, any*, double) boolean

The geo_near funcion is converted internally to ageo_within_distance function, with an an (implicit) order by thedistance between the two geometries. However, if the query hasan (explicit) order-by already, the function performs no ordering bydistance. The geo_near function can appear only in the WHEREclause, and must be a top-level predicate. The geo_near functioncannot be nested under an OR or NOT operator.

geo_distance(any*, any*) double Raises an error at compile time if the function detects that anoperand will not return a single valid GeoJson object. Otherwise,the runtime behavior is as follows:• Returns -1 if any of the operands returns zero or more than 1

item.• Returns -1 if any of the operands is not a geometry.• Returns NULL if any operand returns NULL.• Otherwise the function returns the geodetic distance between

the 2 input geometries. The returned distance is the minimumamong the distances of any pair of points, where the firstpoint belongs to the first geometry and the second point to thesecond geometry. Between two such points, their distance isthe length of the geodetic line that connects the points.

geo_is_geometry(any*) boolean

• Returns false if an operand returns zero or more than 1 item.• Returns NULL if an operand returns NULL.• Returns true if the input is a single valid GeoJson object.

Otherwise, false.

Chapter 5Searching GeoJSON Data

5-6

Page 62: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

6Working With Indexes

The SQL for Oracle NoSQL Database query processor can detect which of theexisting indexes on a table can be used to optimize the execution of a query. Thischapter provides a brief examples-based introduction to index creation, and queriesusing indexes. For a more detailed description of index creation and usage, see thesee the SQL for Oracle NoSQL Database Specification.

To make it possible to fit the example output on the page, the examples in this chapteruse mode LINE.

Basic IndexingThis section builds on the examples that you began in Working with complex data.

sql-> mode LINEQuery output mode is LINEsql-> create index idx_income on Persons (income);Statement completed successfullysql-> create index idx_age on Persons (age);Statement completed successfullysql-> SELECT * from PersonsWHERE income > 10000000 and age < 40;

> Row 0 +-------------+--------------------------------------------+ | id | 3 | +-------------+--------------------------------------------+ | firstname | John | +-------------+--------------------------------------------+ | lastname | Morgan | +-------------+--------------------------------------------+ | age | 38 | +-------------+--------------------------------------------+ | income | 100000000 | +-------------+--------------------------------------------+ | lastLogin | 2016-11-29T08:21:35.4971 | +-------------+--------------------------------------------+ | address | street | 187 Aspen Drive | | | city | Middleburg | | | state | FL | | | zipcode | NULL | | | phones | | | type | work | | | areacode | 305 | | | number | 1234079 | | | | | | type | home | | | areacode | 305 |

6-1

Page 63: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| | number | 2066401 | +-------------+--------------------------------------------+ | connections | 1 | | | 4 | | | 2 | +-------------+--------------------------------------------+ | expenses | food | 2000 | | | gas | 10 | | | travel | 700 | +-------------+--------------------------------------------+

1 row returned

Using Index HintsIn the previous section, both indexes are applicable. For index idx_income, the querycondition income > 10000000 can be used as the starting point for an index scan thatwill retrieve only the index entries and associated table rows that satisfy this condition.Similarly, for index idx_age, the condition age < 40 can be used as the stopping pointfor the index scan. SQL for Oracle NoSQL Database has no way of knowing which ofthe 2 predicates is more selective, and it assigns the same "value" to each index,eventually picking the one whose name is first alphabetically. In the previous example,idx_age was used. To choose the idx_income index instead, the query should bewritten with an index hint:

sql-> SELECT /*+ FORCE_INDEX(Persons idx_income) */ * from PersonsWHERE income > 10000000 and age < 40;

> Row 0 +-------------+--------------------------------------------+ | id | 3 | +-------------+--------------------------------------------+ | firstname | John | +-------------+--------------------------------------------+ | lastname | Morgan | +-------------+--------------------------------------------+ | age | 38 | +-------------+--------------------------------------------+ | income | 100000000 | +-------------+--------------------------------------------+ | lastLogin | 2016-11-29T08:21:35.4971 | +-------------+--------------------------------------------+ | address | street | 187 Aspen Drive | | | city | Middleburg | | | state | FL | | | zipcode | NULL | | | phones | | | type | work | | | areacode | 305 | | | number | 1234079 | | | | | | type | home | | | areacode | 305 | | | number | 2066401 |

Chapter 6Using Index Hints

6-2

Page 64: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

+-------------+--------------------------------------------+ | connections | 1 | | | 4 | | | 2 | +-------------+--------------------------------------------+ | expenses | food | 2000 | | | gas | 10 | | | travel | 700 | +-------------+--------------------------------------------+

1 row returned

As shown above, hints are written as a special kind of comment that must be placedimmediately after the SELECT keyword. What distinguishes a hint from a regularcomment is the "+" character immediately after (without any space) the opening "/*".

Complex IndexesThe following example demonstrates indexing of multiple table fields, indexing ofnested fields, and the use of "filtering" predicates during index scans.

sql-> create index idx_state_city_income onPersons (address.state, address.city, income);Statement completed successfullysql-> SELECT * from Persons p WHERE p.address.state = "MA"and income > 79000;

> Row 0 +-------------+------------------------------------------------+ | id | 4 | +-------------+------------------------------------------------+ | firstname | Peter | +-------------+------------------------------------------------+ | lastname | Smith | +-------------+------------------------------------------------+ | age | 38 | +-------------+------------------------------------------------+ | income | 80000 | +-------------+------------------------------------------------+ | lastLogin | 2016-10-19T09:18:05.5555 | +-------------+------------------------------------------------+ | address | street | 364 Mulberry Street | | | city | Leominster | | | state | MA | | | zipcode | NULL | | | phones | | | type | work | | | areacode | 339 | | | number | 4120211 | | | | | | type | work | | | areacode | 339 | | | number | 8694021 | | | |

Chapter 6Complex Indexes

6-3

Page 65: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| | type | home | | | areacode | 339 | | | number | 1205678 | | | | | | type | home | | | areacode | 305 | | | number | 8064321 | +-------------+------------------------------------------------+ | connections | 3 | | | 5 | | | 1 | | | 2 | +-------------+------------------------------------------------+ | expenses | books | 240 | | | clothes | 2000 | | | food | 6000 | | | shoes | 1200 | +-------------+------------------------------------------------+

1 row returned

Index idx_state_city_income is applicable to the above query. Specifically, the state ="MA" condition can be used to establish the boundaries of the index scan (only indexentries whose first field is "MA" will be scanned). Further, during the index scan, theincome condition can be used as a "filtering" condition, to skip index entries whosethird field is less or equal to 79000. As a result, only rows that satisfy both conditionsare retrieved from the table.

Multi-Key IndexesA multi-key index indexes all the elements of an array, or all the elements and/or allthe keys of a map. For such indexes, for each table row, the index contains as manyentries as the number of elements/entries in the array/map that is being indexed. Onlyone array/map may be indexed.

sql-> create index idx_areacode onPersons (address.phones[].areacode);Statement completed successfullysql-> SELECT * FROM Persons p WHERE p.address.phones.areacode =any 339;

> Row 0 +-------------+------------------------------------------------+ | id | 2 | +-------------+------------------------------------------------+ | firstname | John | +-------------+------------------------------------------------+ | lastname | Anderson | +-------------+------------------------------------------------+ | age | 35 | +-------------+------------------------------------------------+ | income | 100000 | +-------------+------------------------------------------------+ | lastLogin | 2016-11-28T13:01:11.2088 |

Chapter 6Multi-Key Indexes

6-4

Page 66: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

+-------------+------------------------------------------------+ | address | street | 187 Hill Street | | | city | Beloit | | | state | WI | | | zipcode | 53511 | | | phones | | | type | home | | | areacode | 339 | | | number | 1684972 | +-------------+------------------------------------------------+ | connections | 1 | | | 3 | +-------------+------------------------------------------------+ | expenses | books | 100 | | | food | 1700 | | | travel | 2100 | +-------------+------------------------------------------------+

> Row 1 +-------------+------------------------------------------------+ | id | 4 | +-------------+------------------------------------------------+ | firstname | Peter | +-------------+------------------------------------------------+ | lastname | Smith | +-------------+------------------------------------------------+ | age | 38 | +-------------+------------------------------------------------+ | income | 80000 | +-------------+------------------------------------------------+ | lastLogin | 2016-10-19T09:18:05.5555 | +-------------+------------------------------------------------+ | address | street | 364 Mulberry Street | | | city | Leominster | | | state | MA | | | zipcode | NULL | | | phones | | | type | work | | | areacode | 339 | | | number | 4120211 | | | | | | type | work | | | areacode | 339 | | | number | 8694021 | | | | | | type | home | | | areacode | 339 | | | number | 1205678 | | | | | | type | home | | | areacode | 305 | | | number | 8064321 | +-------------+------------------------------------------------+ | connections | 3 | | | 5 |

Chapter 6Multi-Key Indexes

6-5

Page 67: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| | 1 | | | 2 | +-------------+------------------------------------------------+ | expenses | books | 240 | | | clothes | 2000 | | | food | 6000 | | | shoes | 1200 | +-------------+------------------------------------------------+

> Row 2 +-------------+----------------------------------------------+ | id | 5 | +-------------+----------------------------------------------+ | firstname | Dana | +-------------+----------------------------------------------+ | lastname | Scully | +-------------+----------------------------------------------+ | age | 47 | +-------------+----------------------------------------------+ | income | 400000 | +-------------+----------------------------------------------+ | lastLogin | 2016-11-08T09:16:46.3929 | +-------------+----------------------------------------------+ | address | street | 427 Linden Avenue | | | city | Monroe Township | | | state | NJ | | | zipcode | NULL | | | phones | | | type | work | | | areacode | 201 | | | number | 3213267 | | | | | | type | work | | | areacode | 201 | | | number | 8765421 | | | | | | type | home | | | areacode | 339 | | | number | 3414578 | +-------------+----------------------------------------------+ | connections | 2 | | | 4 | | | 1 | | | 3 | +-------------+----------------------------------------------+ | expenses | clothes | 1500 | | | food | 900 | | | shoes | 1000 | +-------------+----------------------------------------------+

3 rows returned

In the above example, a multi-key index is created on all the area codes in thePersons table, mapping each area code to the persons that have a phone number with

Chapter 6Multi-Key Indexes

6-6

Page 68: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

that area code. The query is looking for persons who have a phone number with areacode 339. The index is applicable to the query and so the key 339 will be searched forin the index and all the associated table rows will be retrieved.

sql-> create index idx_expenses onPersons (expenses.keys(), expenses.values());Statement completed successfullysql-> SELECT * FROM Persons p WHERE p.expenses.food > 1000;

> Row 0 +-------------+--------------------------------------------+ | id | 2 | +-------------+--------------------------------------------+ | firstname | John | +-------------+--------------------------------------------+ | lastname | Anderson | +-------------+--------------------------------------------+ | age | 35 | +-------------+--------------------------------------------+ | income | 100000 | +-------------+--------------------------------------------+ | lastLogin | 2016-11-28T13:01:11.2088 | +-------------+--------------------------------------------+ | address | street | 187 Hill Street | | | city | Beloit | | | state | WI | | | zipcode | 53511 | | | phones | | | type | home | | | areacode | 339 | | | number | 1684972 | +-------------+--------------------------------------------+ | connections | 1 | | | 3 | +-------------+--------------------------------------------+ | expenses | books | 100 | | | food | 1700 | | | travel | 2100 | +-------------+--------------------------------------------+

> Row 1 +-------------+--------------------------------------------+ | id | 3 | +-------------+--------------------------------------------+ | firstname | John | +-------------+--------------------------------------------+ | lastname | Morgan | +-------------+--------------------------------------------+ | age | 38 | +-------------+--------------------------------------------+ | income | 100000000 | +-------------+--------------------------------------------+ | lastLogin | 2016-11-29T08:21:35.4971 | +-------------+--------------------------------------------+ | address | street | 187 Aspen Drive |

Chapter 6Multi-Key Indexes

6-7

Page 69: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| | city | Middleburg | | | state | FL | | | zipcode | NULL | | | phones | | | type | work | | | areacode | 305 | | | number | 1234079 | | | | | | type | home | | | areacode | 305 | | | number | 2066401 | +-------------+--------------------------------------------+ | connections | 1 | | | 4 | | | 2 | +-------------+--------------------------------------------+ | expenses | food | 2000 | | | gas | 10 | | | travel | 700 | +-------------+--------------------------------------------+

> Row 2 +-------------+------------------------------------------------+ | id | 4 | +-------------+------------------------------------------------+ | firstname | Peter | +-------------+------------------------------------------------+ | lastname | Smith | +-------------+------------------------------------------------+ | age | 38 | +-------------+------------------------------------------------+ | income | 80000 | +-------------+------------------------------------------------+ | lastLogin | 2016-10-19T09:18:05.5555 | +-------------+------------------------------------------------+ | address | street | 364 Mulberry Street | | | city | Leominster | | | state | MA | | | zipcode | NULL | | | phones | | | type | work | | | areacode | 339 | | | number | 4120211 | | | | | | type | work | | | areacode | 339 | | | number | 8694021 | | | | | | type | home | | | areacode | 339 | | | number | 1205678 | | | | | | type | home | | | areacode | 305 | | | number | 8064321 |

Chapter 6Multi-Key Indexes

6-8

Page 70: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

+-------------+------------------------------------------------+ | connections | 3 | | | 5 | | | 1 | | | 2 | +-------------+------------------------------------------------+ | expenses | books | 240 | | | clothes | 2000 | | | food | 6000 | | | shoes | 1200 | +-------------+------------------------------------------------+

3 rows returned

In the above example, a multi-key index is created on all the expenses entries in thePersons table, mapping each category C and each amount A associated with thatcategory to the persons that have an entry (C, A) in their expenses map. The query islooking for persons who spent more than 1000 on food. The index is applicable to thequery and so only the index entries whose first field (the map key) is equal to "food"and second key (the amount) is greater than 1000 will be scanned and the associatedrows retrieved.

Indexing JSON DataAn index is a JSON index if it indexes at least one field that is contained inside JSONdata.

Because JSON is schema-less, it is possible for JSON data to differ in type acrosstable rows. However, when indexing JSON data, the data type must be consistentacross table rows or the index creation will fail. Further, once one or more JSONindexes have been created, any attempt to write data of an incorrect type will fail.

With the exception of the previous restriction, indexing JSON data and working withJSON indexes behaves in much the same way as indexing non-JSON data. To createthe index, specify a path to the JSON field using dot notation. You must also specifythe data's type, using the AS keyword.

The following examples are built on the examples shown in Working with JSON.

sql-> create index idx_json_income on JSONPersons (person.income as integer);Statement completed successfullysql-> create index idx_json_age on JSONPersons (person.age as integer);Statement completed successfullysql->

You can then run a query in the normal way, and the index idx_json_income will beautomatically used. But as shown at the beginning of this chapter (Basic Indexing), thequery processor will not know which index to use. To require the use of a particularindex provide an index hint as normal:

sql-> SELECT /*+ FORCE_INDEX(JSONPersons idx_json_income) */ * from JSONPersons j WHERE j.person.income > 10000000 and j.person.age < 40;

Chapter 6Indexing JSON Data

6-9

Page 71: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

> Row 0 +-----------+---------------------------------------------+ | id | 3 | +-----------+---------------------------------------------+ | person | address | | | city | Middleburg | | | phones | | | areacode | 305 | | | number | 1234079 | | | type | work | | | | | | areacode | 305 | | | number | 2066401 | | | type | home | | | state | FL | | | street | 187 Aspen Drive | | | age | 38 | | | connections | | | 1 | | | 4 | | | 2 | | | expenses | | | food | 2000 | | | gas | 10 | | | travel | 700 | | | firstname | John | | | income | 100000000 | | | lastLogin | 2016-11-29T08:21:35.4971 | | | lastname | Morgan | +-----------+---------------------------------------------+

1 row returnedsql->

Finally, when creating a multi-key index on a JSON map, a type must not be given forthe .keys() expression. This is because the type will always be String. However, atype declaration is required for the .values() expression:

sql-> create index idx_json_expenses on JSONPersons (person.expenses.keys(), person.expenses.values() as integer);Statement completed successfullysql-> SELECT * FROM JSONPersons j WHERE j.person.expenses.food > 1000;

> Row 0 +-----------+---------------------------------------------+ | id | 2 | +-----------+---------------------------------------------+ | person | address | | | city | Beloit | | | phones | | | areacode | 339 | | | number | 1684972 | | | type | home |

Chapter 6Indexing JSON Data

6-10

Page 72: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| | state | WI | | | street | 187 Hill Street | | | zipcode | 53511 | | | age | 35 | | | connections | | | 1 | | | 3 | | | expenses | | | books | 100 | | | food | 1700 | | | travel | 2100 | | | firstname | John | | | income | 100000 | | | lastLogin | 2016-11-28T13:01:11.2088 | | | lastname | Anderson | +-----------+---------------------------------------------+

> Row 1 +-----------+---------------------------------------------+ | id | 3 | +-----------+---------------------------------------------+ | person | address | | | city | Middleburg | | | phones | | | areacode | 305 | | | number | 1234079 | | | type | work | | | | | | areacode | 305 | | | number | 2066401 | | | type | home | | | state | FL | | | street | 187 Aspen Drive | | | age | 38 | | | connections | | | 1 | | | 4 | | | 2 | | | expenses | | | food | 2000 | | | gas | 10 | | | travel | 700 | | | firstname | John | | | income | 100000000 | | | lastLogin | 2016-11-29T08:21:35.4971 | | | lastname | Morgan | +-----------+---------------------------------------------+

> Row 2 +-----------+---------------------------------------------+ | id | 4 | +-----------+---------------------------------------------+ | person | address | | | city | Leominster | | | phones |

Chapter 6Indexing JSON Data

6-11

Page 73: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| | areacode | 339 | | | number | 4120211 | | | type | work | | | | | | areacode | 339 | | | number | 8694021 | | | type | work | | | | | | areacode | 339 | | | number | 1205678 | | | type | home | | | null | | | | | | areacode | 305 | | | number | 8064321 | | | type | home | | | state | MA | | | street | 364 Mulberry Street | | | age | 38 | | | connections | | | 3 | | | 5 | | | 1 | | | 2 | | | expenses | | | books | 240 | | | clothes | 2000 | | | food | 6000 | | | shoes | 1200 | | | firstname | Peter | | | income | 80000 | | | lastLogin | 2016-10-19T09:18:05.5555 | | | lastname | Smith | +-----------+---------------------------------------------+

3 rows returnedsql->

Be aware that all the other constraints that apply to a non-JSON multi-keyed indexalso apply to a JSON multi-keyed index.

Chapter 6Indexing JSON Data

6-12

Page 74: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

7Working with Table Rows

This chapter provides examples on how to insert and update table rows using SQL forOracle NoSQL Database INSERT and UPDATE statements.

Adding Table Rows using INSERT and UPSERTThis topic provides examples on how to add table rows using the SQL for OracleNoSQL Database INSERT and UPSERT statements.

You use the INSERT statement to insert or update a single row in an existing table.

Examples:

If you executed the SQLBasicExamples Script in Chapter 2, you should already havecreated the table named Users. The table had this definition:

CREATE TABLE Users ( id integer, firstname string, lastname string, age integer, income integer, primary key (id)); sql-> describe table Users; === Information === +-------+-----+-------+----------+----------+--------+----------+---------+-------------+ | name | ttl | owner | sysTable | r2compat | parent | children | indexes | description | +-------+-----+-------+----------+----------+--------+----------+---------+-------------+ | Users | | | N | N | | | | | +-------+-----+-------+----------+----------+--------+----------+---------+-------------+

=== Fields === +----+-----------+---------+----------+-----------+----------+------------+----------+ | id | name | type | nullable | default | shardKey | primaryKey | identity | +----+-----------+---------+----------+-----------+----------+------------+----------+ | 1 | id | Integer | N | NullValue | Y | Y | |

7-1

Page 75: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

+----+-----------+---------+----------+-----------+----------+------------+----------+ | 2 | firstname | String | Y | NullValue | | | | +----+-----------+---------+----------+-----------+----------+------------+----------+ | 3 | lastname | String | Y | NullValue | | | | +----+-----------+---------+----------+-----------+----------+------------+----------+ | 4 | age | Integer | Y | NullValue | | | | +----+-----------+---------+----------+-----------+----------+------------+----------+ | 5 | income | Integer | Y | NullValue | | | | +----+-----------+---------+----------+-----------+----------+------------+----------+

To insert a new row into the Users table, use the INSERT statement as follows.Because you are adding values to all table columns, you do not need to specifycolumn names explicitly:

sql-> INSERT INTO Users VALUES (10, "John", "Smith", 22, 45000);{"NumRowsInserted":1}1 row returnedsql-> select * from Users;{"id":10,"firstname":"John","lastname":"Smith","age":22,"income":45000}

To insert data into some, but not all, table columns, specify the column namesexplicitly in the INSERT statement. Any columns that you do not specify are assignedeither NULL or the default value supplied when you created the table:

sql-> INSERT INTO Users (id, firstname, income)VALUES (11, "Mary", 5000);{"NumRowsInserted":1}1 row returned

sql-> select * from Users;{"id":11,"firstname":"Mary","lastname":null,"age":null,"income":5000}{"id":10,"firstname":"John","lastname":"Smith","age":22,"income":45000}2 rows returned

Using the UPSERT Statement

The word UPSERT combines UPDATE and INSERT, describing it statement's function. Usean UPSERT statement to insert a row where it does not exist, or to update the row withnew values when it does.

For example, if you already inserted a new row as described in the previous section,executing the next statement updates user John’s age to 27, and income to 60,000. If

Chapter 7Adding Table Rows using INSERT and UPSERT

7-2

Page 76: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

you did not execute the previous INSERT statement, the UPSERT statement inserts anew row with user id 10 to the Users table.

sql-> UPSERT INTO Users VALUES (10, "John", "Smith", 27, 60000);{"NumRowsInserted":0}1 row returnedsql-> UPSERT INTO Users VALUES (11, "Mary", "Brown", 28, 70000);{"NumRowsInserted":0}1 row returned

sql-> select * from Users;{"id":10,"firstname":"John","lastname":"Smith","age":22,"income":60000}{"id":11,"firstname":"Mary","lastname":"Brown","age":28,"income":70000}2 rows returned

Using an IDENTITY Column

You can use IDENTITY columns to automatically generate values for a table columneach time you insert a new table row. To learn more, see Defining Tables With anIDENTITY Column.

Here are a few examples for how to use the INSERT statements for both flavors of anIDENTITY column:

• GENERATED ALWAYS AS IDENTITY

• GENERATED BY DEFAULT [ON NULL] AS IDENTITY

Create a table named Employee_test using one column, DeptId, as GENERATEDALWAYS AS IDENTITY. This IDENTITY column is not the primary key. Insert a fewrows into the table.

sql-> CREATE TABLE EmployeeTest( Empl_id INTEGER, Name STRING, DeptId INTEGER GENERATED ALWAYS AS IDENTITY (CACHE 1), PRIMARY KEY(Empl_id));

INSERT INTO Employee_test VALUES (148, 'Sally', DEFAULT);INSERT INTO Employee_test VALUES (250, 'Joe', DEFAULT);INSERT INTO Employee_test VALUES (346, 'Dave', DEFAULT);

The INSERT statement inserts the following rows with the system generates values 1,2, and 3 for the IDENTITY column DeptId.

Empl_id Name DeptId

148 Sally 1

250 Joe 2

346 Dave 3

Chapter 7Adding Table Rows using INSERT and UPSERT

7-3

Page 77: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

You cannot specify a value for the DeptId IDENTITY column when inserting a row tothe Employee_test table, because you defined that column as GENERATED ALWAYS ASIDENTITY. Specifying DEFAULT as the column value, the system generates the nextIDENTITY value. Conversely, trying to execute the following SQL statement causes anexception, because you supply a value (200) for the DeptId column.

sql-> INSERT INTO Employee_test VALUES (566, 'Jane', 200);

If you create the column as GENERATED BY DEFAULT AS IDENTITY for theEmployee_test table, the system generates a value only if you fail to supply one. Forexample, if you define the Employee_test table as follows, then execute the INSERTstatement as above, the statement inserts the value 200 for the employee’s DeptIdcolumn.

CREATE Table Employee_test( Empl_id INTEGER, Name STRING, DeptId INTEGER GENERATED BY DEFAULT AS IDENTITY (CACHE 1), PRIMARY KEY(Empl_id));

Modifying Table Rows using UPDATE StatementsThis topic provides examples of how to update table rows using SQL for OracleNoSQL Database UPDATE statements. These are an efficient way to update table rowdata, because UPDATE statements make server-side updates directly, withoutrequiring a Read/Modify/Write update cycle.

Note:

You can use UPDATE statements to update only an existing row. Youcannot use UPDATE to either create new rows, or delete existing rows. AnUPDATE statement can modify only a single row at a time.

The UPDATE statement syntax is described in Update Statement Syntax.

Example DataThis chapter's examples uses the data loaded by the SQLJSONExamples script, whichcan be found in the Examples download package. For details on using this script, thesample data it loads, and the Examples download, see See SQLJSONExamplesScript.

Chapter 7Modifying Table Rows using UPDATE Statements

7-4

Page 78: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Changing Field ValuesIn the simplest case, you can change the value of a field using the Update StatementSET clause. The JSON example data set has a row which contains just an array andan integer. This is row ID 6:

sql-> mode columnQuery output mode is COLUMNsql-> SELECT * from JSONPersons j WHERE j.id = 6; +----+-------------------+ | id | person | +----+-------------------+ | 6 | myarray | | | 1 | | | 2 | | | 3 | | | 4 | | | mynumber | 5 | +----+-------------------+

1 row returned

You can change the value of mynumber in that row using the following statement:

sql-> UPDATE JSONPersons j SET j.person.mynumber = 100 WHERE j.id = 6; +----------+ | Column_1 | +----------+ | 1 | +----------+

1 row returnedsql-> SELECT * from JSONPersons j WHERE j.id = 6; +----+-------------------+ | id | person | +----+-------------------+ | 6 | myarray | | | 1 | | | 2 | | | 3 | | | 4 | | | mynumber | 100 | +----+-------------------+

1 row returned

In the previous example, the results returned by the Update statement was not veryinformative, so we were required to reissue the Select statement in order to view the

Chapter 7Modifying Table Rows using UPDATE Statements

7-5

Page 79: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

results of the update. You can avoid that by using a RETURNING clause. Thisfunctions exactly like a Select statement:

sql-> UPDATE JSONPersons j SET j.person.mynumber = 200 WHERE j.id = 6 RETURNING *; +----+-------------------+ | id | person | +----+-------------------+ | 6 | myarray | | | 1 | | | 2 | | | 3 | | | 4 | | | mynumber | 200 | +----+-------------------+

1 row returnedsql->

You can further limit and customize the displayed results in the same way that you cando so using a SELECT statement:

sql-> UPDATE JSONPersons j SET j.person.mynumber = 300 WHERE j.id = 6 RETURNING id, j.person.mynumber AS MyNumber; +----+---------------------+ | id | MyNumber | +----+---------------------+ | 6 | 300 | +----+---------------------+

1 row returnedsql->

It is normally possible to update the value of a non-JSON field using the SET clause.However, you cannot change a field if it is a primary key. For example:

sql-> UPDATE JSONPersons j SET j.id = 1000 WHERE j.id = 6 RETURNING *;Error handling command UPDATE JSONPersons jSET j.id = 1000WHERE j.id = 6RETURNING *: Error: at (2, 4) Cannot update a primary key columnUsage:

Unknown statement

sql->

Chapter 7Modifying Table Rows using UPDATE Statements

7-6

Page 80: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Modifying Array ValuesYou use the Update statement ADD clause to add elements into an array. You use aSET clause to change the value of an existing array element. And you use a REMOVEclause to remove elements from an array.

Adding Elements to an ArrayThe ADD clause requires you to identify the array position that you want to operate on,followed by the value you want to set to that position in the array. If the index valuethat you set is 0 or a negative number, the value that you specify is inserted at thebeginning of the array.

If you do not provide an index position, the array value that you specify is appended tothe end of the array.

sql-> SELECT * from JSONPersons j WHERE j.id = 6; +----+-------------------+ | id | person | +----+-------------------+ | 6 | myarray | | | 1 | | | 2 | | | 3 | | | 4 | | | mynumber | 300 | +----+-------------------+

1 row returnedsql-> UPDATE JSONPersons j ADD j.person.myarray 0 50, ADD j.person.myarray 100 WHERE j.id = 6 RETURNING *; +----+-------------------+ | id | person | +----+-------------------+ | 6 | myarray | | | 50 | | | 1 | | | 2 | | | 3 | | | 4 | | | 100 | | | mynumber | 300 | +----+-------------------+

1 row returnedsql->

Notice that multiple ADD clauses are used in the query above.

Chapter 7Modifying Table Rows using UPDATE Statements

7-7

Page 81: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Array values get appended to the end of the array, even if you provide an arrayposition that is larger than the size of the array. You can either provide an arbitrarilylarge number, or make use of the size() function:

sql-> UPDATE JSONPersons j ADD j.person.myarray (size(j.person.myarray) + 1) 400 WHERE j.id = 6 RETURNING *; +----+-------------------+ | id | person | +----+-------------------+ | 6 | myarray | | | 50 | | | 1 | | | 2 | | | 3 | | | 4 | | | 100 | | | 400 | | | mynumber | 300 | +----+-------------------+

1 row returnedsql->

You can append values to the array using the built-in seq_concat() function:

sql-> UPDATE JSONPersons j ADD j.person.myarray seq_concat(66, 77, 88) WHERE j.id = 6 RETURNING *; +----+-------------------+ | id | person | +----+-------------------+ | 6 | myarray | | | 50 | | | 1 | | | 2 | | | 3 | | | 4 | | | 100 | | | 400 | | | 66 | | | 77 | | | 88 | | | mynumber | 300 | +----+-------------------+

1 row returnedsql->

Chapter 7Modifying Table Rows using UPDATE Statements

7-8

Page 82: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

If you provide an array position that is between 0 and the array's size, then the valueyou specify will be inserted into the array before the specified position. To determinethe correct position, start counting from 0:

UPDATE JSONPersons j ADD j.person.myarray 3 250 WHERE j.id = 6 RETURNING *; +----+-------------------+ | id | person | +----+-------------------+ | 6 | myarray | | | 50 | | | 1 | | | 2 | | | 250 | | | 3 | | | 4 | | | 100 | | | 400 | | | 66 | | | 77 | | | 88 | | | mynumber | 300 | +----+-------------------+

1 row returnedsql->

Changing an Existing Element in an ArrayTo change an existing value in an array, use the SET clause and identify the value'sposition using []. To determine the value's position, start counting from 0:

sql-> UPDATE JSONPersons j SET j.person.myarray[3] = 1000 WHERE j.id = 6 RETURNING *; +----+-------------------+ | id | person | +----+-------------------+ | 6 | myarray | | | 50 | | | 1 | | | 2 | | | 1000 | | | 3 | | | 4 | | | 100 | | | 400 | | | 66 | | | 77 | | | 88 | | | mynumber | 300 |

Chapter 7Modifying Table Rows using UPDATE Statements

7-9

Page 83: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

+----+-------------------+

1 row returnedsql->

Removing Elements from ArraysTo remove an existing element from an array, use the REMOVE clause. To do this,you must identify the position of the element in the array that you want to remove. Todetermine the value's position, start counting from 0:

sql-> UPDATE JSONPersons j REMOVE j.person.myarray[3] WHERE j.id = 6 RETURNING *; +----+-------------------+ | id | person | +----+-------------------+ | 6 | myarray | | | 50 | | | 1 | | | 2 | | | 3 | | | 4 | | | 100 | | | 400 | | | 66 | | | 77 | | | 88 | | | mynumber | 300 | +----+-------------------+

1 row returnedsql->

It is possible for the array position to be identified by an expression. For example, inour sample data, some records include an array of phone numbers, and some of thosephone numbers include a work number:

sql-> SELECT * FROM JSONPersons j WHERE j.id = 3; +----+---------------------------------------------+ | id | person | +----+---------------------------------------------+ | 3 | address | | | city | Middleburg | | | phones | | | areacode | 305 | | | number | 1234079 | | | type | work | | | | | | areacode | 305 | | | number | 2066401 | | | type | home |

Chapter 7Modifying Table Rows using UPDATE Statements

7-10

Page 84: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| | state | FL | | | street | 187 Aspen Drive | | | age | 38 | | | connections | | | 1 | | | 4 | | | 2 | | | expenses | | | food | 2000 | | | gas | 10 | | | travel | 700 | | | firstname | John | | | income | 100000000 | | | lastLogin | 2016-11-29T08:21:35.4971 | | | lastname | Morgan | +----+---------------------------------------------+

1 row returnedsql->

We can remove the work number from the array in one of two ways. First, we candirectly specify its position in the array (position 0), but that only removes a singleelement at a time. If we want to remove all the work numbers, we can do it by usingthe $element variable. To illustrate, we first add another work number to the array:

sql-> UPDATE JSONPersons j ADD j.person.address.phones 0 {"type":"work", "areacode":415, "number":9998877} WHERE j.id = 3 RETURNING *; +----+---------------------------------------------+ | id | person | +----+---------------------------------------------+ | 3 | address | | | city | Middleburg | | | phones | | | areacode | 415 | | | number | 9998877 | | | type | work | | | | | | areacode | 305 | | | number | 1234079 | | | type | work | | | | | | areacode | 305 | | | number | 2066401 | | | type | home | | | state | FL | | | street | 187 Aspen Drive | | | age | 38 | | | connections | | | 1 | | | 4 | | | 2 |

Chapter 7Modifying Table Rows using UPDATE Statements

7-11

Page 85: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| | expenses | | | food | 2000 | | | gas | 10 | | | travel | 700 | | | firstname | John | | | income | 100000000 | | | lastLogin | 2016-11-29T08:21:35.4971 | | | lastname | Morgan | +----+---------------------------------------------+

1 row returnedsql->

Now we can remove all the work numbers as follows:

sql-> UPDATE JSONPersons j REMOVE j.person.address.phones[$element.type = "work"] WHERE j.id = 3 RETURNING *; +----+---------------------------------------------+ | id | person | +----+---------------------------------------------+ | 3 | address | | | city | Middleburg | | | phones | | | areacode | 305 | | | number | 2066401 | | | type | home | | | state | FL | | | street | 187 Aspen Drive | | | age | 38 | | | connections | | | 1 | | | 4 | | | 2 | | | expenses | | | food | 2000 | | | gas | 10 | | | travel | 700 | | | firstname | John | | | income | 100000000 | | | lastLogin | 2016-11-29T08:21:35.4971 | | | lastname | Morgan | +----+---------------------------------------------+

1 row returnedsql->

Modifying Map ValuesTo write a new field to a map, use the PUT clause. You can also use the PUT clauseto change an existing map value. To remove a map field, use the REMOVE clause.

Chapter 7Modifying Table Rows using UPDATE Statements

7-12

Page 86: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

For example, consider the following two rows from our sample data:

sql-> SELECT * FROM JSONPersons j WHERE j.id = 6 OR j.id = 3; +----+---------------------------------------------+ | id | person | +----+---------------------------------------------+ | 3 | address | | | city | Middleburg | | | phones | | | areacode | 305 | | | number | 2066401 | | | type | home | | | state | FL | | | street | 187 Aspen Drive | | | age | 38 | | | connections | | | 1 | | | 4 | | | 2 | | | expenses | | | food | 2000 | | | gas | 10 | | | travel | 700 | | | firstname | John | | | income | 100000000 | | | lastLogin | 2016-11-29T08:21:35.4971 | | | lastname | Morgan | +----+---------------------------------------------+ | 6 | myarray | | | 50 | | | 1 | | | 2 | | | 3 | | | 4 | | | 100 | | | 400 | | | 66 | | | 77 | | | 88 | | | mynumber | 300 | +----+---------------------------------------------+

2 rows returned sql->

These two rows look nothing alike. Row 3 contains information about a person, whilerow 6 contains, essentially, random data. This is possible because the person columnis of type JSON, which is not strongly typed. But because we interact with JSONcolumns as if they are maps, we can fix row 6 by modifying it as a map.

Chapter 7Modifying Table Rows using UPDATE Statements

7-13

Page 87: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Removing Elements from a MapTo begin, we remove the two existing elements from row six (myarray and mynumber).We do this with a single UPDATE statement, which allows us to execute multipleupdate clauses so long as they are comma-separated:

sql-> UPDATE JSONPersons j REMOVE j.person.myarray, REMOVE j.person.mynumber WHERE j.id = 6 RETURNING *; +----+-----------------+ | id | person | +----+-----------------+ | 6 | | +----+-----------------+

1 row returnedsql->

Adding Elements to a MapNext, we add person data to this table row. We could do this with a single UPDATEstatement by specifying the entire map with a single PUT clause, but for illustrationpurposes we do this in multiple steps.

To begin, we specify the person's name. Here, we use a single PUT clause thatspecifies a map with multiple elements:

sql-> UPDATE JSONPersons j PUT j.person {"firstname" : "Wendy", "lastname" : "Purvis"} WHERE j.id = 6 RETURNING *; +----+--------------------+ | id | person | +----+--------------------+ | 6 | firstname | Wendy | | | lastname | Purvis | +----+--------------------+

1 row returnedsql->

Next, we specify the age, connections, expenses, income, and lastLogin fields usingmultiple PUT clauses on a single UPDATE statement:

sql-> UPDATE JSONPersons j PUT j.person {"age" : 43}, PUT j.person {"connections" : [2,3]}, PUT j.person {"expenses" : {"food" : 1100, "books" : 210,

Chapter 7Modifying Table Rows using UPDATE Statements

7-14

Page 88: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

"travel" : 50}}, PUT j.person {"income" : 80000}, PUT j.person {"lastLogin" : "2017-06-29T16:12:35.0285"} WHERE j.id = 6 RETURNING *; +----+----------------------------------------+ | id | person | +----+----------------------------------------+ | 6 | age | 43 | | | connections | | | 2 | | | 3 | | | expenses | | | books | 210 | | | food | 1100 | | | travel | 50 | | | firstname | Wendy | | | income | 80000 | | | lastLogin | 2017-06-29T16:12:35.0285 | | | lastname | Purvis | +----+----------------------------------------+

1 row returnedsql->

We still need an address. Again, we could do this with a single PUT clause, but forillustration purposes we will use multiple clauses. Our first PUT creates the addresselement, which uses a map as a value. Our second PUT adds elements to theaddress map:

sql-> UPDATE JSONPersons j PUT j.person {"address" : {"street" : "479 South Way Dr"}}, PUT j.person.address {"city" : "St. Petersburg", "state" : "FL"} WHERE j.id = 6 RETURNING *; +----+----------------------------------------+ | id | person | +----+----------------------------------------+ | 6 | address | | | city | St. Petersburg | | | state | FL | | | street | 479 South Way Dr | | | age | 43 | | | connections | | | 2 | | | 3 | | | expenses | | | books | 210 | | | food | 1100 | | | travel | 50 | | | firstname | Wendy | | | income | 80000 | | | lastLogin | 2017-06-29T16:12:35.0285 |

Chapter 7Modifying Table Rows using UPDATE Statements

7-15

Page 89: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| | lastname | Purvis | +----+----------------------------------------+

1 row returnedsql->

Finally, we provide phone numbers for this person. These are specified as an array ofmaps:

sql-> UPDATE JSONPersons j PUT j.person.address {"phones" : [{"type":"work", "areacode":727, "number":8284321}, {"type":"home", "areacode":727, "number":5710076}, {"type":"mobile", "areacode":727, "number":8913080} ] } WHERE j.id = 6 RETURNING *; +----+---------------------------------------------+ | id | person | +----+---------------------------------------------+ | 6 | address | | | city | St. Petersburg | | | phones | | | areacode | 727 | | | number | 8284321 | | | type | work | | | | | | areacode | 727 | | | number | 5710076 | | | type | home | | | | | | areacode | 727 | | | number | 8913080 | | | type | mobile | | | state | FL | | | street | 479 South Way Dr | | | age | 43 | | | connections | | | 2 | | | 3 | | | expenses | | | books | 210 | | | food | 1100 | | | travel | 50 | | | firstname | Wendy | | | income | 80000 | | | lastLogin | 2017-06-29T16:12:35.0285 | | | lastname | Purvis | +----+---------------------------------------------+

1 row returnedsql->

Chapter 7Modifying Table Rows using UPDATE Statements

7-16

Page 90: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Updating Existing Map ElementsTo update an existing element in a map, you can use the PUT clause in exactly thesame way as you add a new element to map. For example, to update the lastLogintime:

sql-> UPDATE JSONPersons j PUT j.person {"lastLogin" : "2017-06-29T20:36:04.9661"} WHERE j.id = 6 RETURNING *; +----+---------------------------------------------+ | id | person | +----+---------------------------------------------+ | 6 | address | | | city | St. Petersburg | | | phones | | | areacode | 727 | | | number | 8284321 | | | type | work | | | | | | areacode | 727 | | | number | 5710076 | | | type | home | | | | | | areacode | 727 | | | number | 8913080 | | | type | mobile | | | state | FL | | | street | 479 South Way Dr | | | age | 43 | | | connections | | | 2 | | | 3 | | | expenses | | | books | 210 | | | food | 1100 | | | travel | 50 | | | firstname | Wendy | | | income | 80000 | | | lastLogin | 2017-06-29T20:36:04.9661 | | | lastname | Purvis | +----+---------------------------------------------+

1 row returnedsql->

Alternatively, use a SET clause:

sql-> UPDATE JSONPersons j SET j.person.lastLogin = "2017-06-29T20:38:56.2751" WHERE j.id = 6 RETURNING *; +----+---------------------------------------------+

Chapter 7Modifying Table Rows using UPDATE Statements

7-17

Page 91: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| id | person | +----+---------------------------------------------+ | 6 | address | | | city | St. Petersburg | | | phones | | | areacode | 727 | | | number | 8284321 | | | type | work | | | | | | areacode | 727 | | | number | 5710076 | | | type | home | | | | | | areacode | 727 | | | number | 8913080 | | | type | mobile | | | state | FL | | | street | 479 South Way Dr | | | age | 43 | | | connections | | | 2 | | | 3 | | | expenses | | | books | 210 | | | food | 1100 | | | travel | 50 | | | firstname | Wendy | | | income | 80000 | | | lastLogin | 2017-06-29T20:38:56.2751 | | | lastname | Purvis | +----+---------------------------------------------+

1 row returnedsql->

If you want to set the timestamp to the current time, use the current_time() built-infunction (see Time Functions):

sql-> UPDATE JSONPersons j SET j.person.lastLogin = cast(current_time() AS String) WHERE j.id = 6 RETURNING *; +----+--------------------------------------------+ | id | person | +----+--------------------------------------------+ | 6 | address | | | city | St. Petersburg | | | phones | | | areacode | 727 | | | number | 8284321 | | | type | work | | | | | | areacode | 727 | | | number | 5710076 |

Chapter 7Modifying Table Rows using UPDATE Statements

7-18

Page 92: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| | type | home | | | | | | areacode | 727 | | | number | 8913080 | | | type | mobile | | | state | FL | | | street | 479 South Way Dr | | | age | 43 | | | connections | | | 2 | | | 3 | | | expenses | | | books | 210 | | | food | 1100 | | | travel | 50 | | | firstname | Wendy | | | income | 80000 | | | lastLogin | 2017-06-29T04:40:15.917 | | | lastname | Purvis | +----+--------------------------------------------+

1 row returnedsql->

If an element in the map is an array, you can modify it in the same way as you wouldany array. For example:

sql-> UPDATE JSONPersons j ADD j.person.connections seq_concat(1, 4) WHERE j.id = 6 RETURNING *; +----+---------------------------------------------+ | id | person | +----+---------------------------------------------+ | 6 | address | | | city | St. Petersburg | | | phones | | | areacode | 727 | | | number | 8284321 | | | type | work | | | | | | areacode | 727 | | | number | 5710076 | | | type | home | | | | | | areacode | 727 | | | number | 8913080 | | | type | mobile | | | state | FL | | | street | 479 South Way Dr | | | age | 43 | | | connections | | | 2 | | | 3 |

Chapter 7Modifying Table Rows using UPDATE Statements

7-19

Page 93: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| | 1 | | | 4 | | | expenses | | | books | 210 | | | food | 1100 | | | travel | 50 | | | firstname | Wendy | | | income | 80000 | | | lastLogin | 2017-06-29T04:40:15.917 | | | lastname | Purvis | +----+---------------------------------------------+

1 row returned

If you are unsure of an element being an array or a map, you can use both ADD andPUT within the same UPDATE statement. For example:

sql-> UPDATE JSONPersons j ADD j.person.connections seq_concat(5, 7), PUT j.person.connections seq_concat(5, 7) WHERE j.id = 6 RETURNING *; +----+---------------------------------------------+ | id | person | +----+---------------------------------------------+ | 6 | address | | | city | St. Petersburg | | | phones | | | areacode | 727 | | | number | 8284321 | | | type | work | | | | | | areacode | 727 | | | number | 5710076 | | | type | home | | | | | | areacode | 727 | | | number | 8913080 | | | type | mobile | | | state | FL | | | street | 479 South Way Dr | | | age | 43 | | | connections | | | 2 | | | 3 | | | 1 | | | 4 | | | 5 | | | 7 | | | expenses | | | books | 210 | | | food | 1100 | | | travel | 50 | | | firstname | Wendy |

Chapter 7Modifying Table Rows using UPDATE Statements

7-20

Page 94: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| | income | 80000 | | | lastLogin | 2017-06-29T04:40:15.917 | | | lastname | Purvis | +----+---------------------------------------------+

1 row returned

If the element is an array, the ADD gets applied and the PUT is a noop. If it is a map,then the PUT gets applied and ADD is a noop. In this example, since the element is anarray, the ADD gets applied.

Managing Time to Live ValuesTime to Live (TTL) values indicate how long data can exist in a table before it expires.Expired data can no longer be returned as part of a query.

Default TTL values can be set on either a table-level or a row level when the table isfirst defined. Using UPDATE statements, you can change the TTL value for a singlerow.

You can see a row's TTL value using the remaining_hours(), remaining_days() orexpiration_time() built-in functions. These TTL functions require a row as input. Weaccomplish this by using the $ as part of the table alias. This causes the table alias tofunction as a row variable.

sql-> SELECT remaining_days($j) AS Expires FROM JSONPersons $j WHERE id = 6; +---------+ | Expires | +---------+ | -1 | +---------+

1 row returnedsql->

The previous query returns -1. This means that the row has no expiration time. Wecan specify an expiration time for the row by using an UPDATE statement with a setTTL clause. This clause computes a new TTL by specifying an offset from the currentexpiration time. If the row never expires, then the current expiration time is1970-01-01T00:00:00.000. The value you provide to set TTL must specify units ofeither HOURS or DAYS.

sql-> UPDATE JSONPersons $j SET TTL 1 DAYS WHERE id = 6 RETURNING remaining_days($j) AS Expires; +---------+ | Expires | +---------+ | 1 | +---------+

Chapter 7Modifying Table Rows using UPDATE Statements

7-21

Page 95: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

1 row returnedsql->

To see the new expiration time, we can use the built-in expiration_time() function.Because we specified an expiration time based on a day boundary, the row expires atmidnight of the following day (expiration rounds up):

sql-> SELECT current_time() AS Now, expiration_time($j) AS Expires FROM JSONPersons $j WHERE id = 6; +-------------------------+-------------------------+ | Now | Expires | +-------------------------+-------------------------+ | 2017-07-03T21:56:47.778 | 2017-07-05T00:00:00.000 | +-------------------------+-------------------------+

1 row returnedsql->

To turn off the TTL so that the row will never expire, specify a negative value, usingeither HOURS or DAYS as the unit:

sql-> UPDATE JSONPersons $j SET TTL -1 DAYS WHERE id = 6 RETURNING remaining_days($j) AS Expires; +---------+ | Expires | +---------+ | 0 | +---------+

1 row returnedsql->

Notice that the RETURNING clause provides a value of 0 days. This indicates that therow will never expire. Further, if we look at the remaining_days() using a SELECTstatement, we will once again see a negative value, indicating that the row neverexpires:

sql-> SELECT remaining_days($j) AS Expires FROM JSONPersons $j WHERE id = 6; +---------+ | Expires | +---------+ | -1 | +---------+

1 row returnedsql->

Chapter 7Modifying Table Rows using UPDATE Statements

7-22

Page 96: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Avoiding the Read-Modify-Write CycleAn important aspect of UPDATE Statements is that you do not have to read a value inorder to update it. Instead, you can blindly modify a value directly in the store withoutever retrieving (reading) it. To do this, you refer to the value you want to modify usingthe $ variable.

For example, we have a row in JSONPersons that looks like this:

sql-> SELECT * FROM JSONPersons WHERE id=6; +----+--------------------------------------------+ | id | person | +----+--------------------------------------------+ | 6 | address | | | city | St. Petersburg | | | phones | | | areacode | 727 | | | number | 8284321 | | | type | work | | | | | | areacode | 727 | | | number | 5710076 | | | type | home | | | | | | areacode | 727 | | | number | 8913080 | | | type | mobile | | | state | FL | | | street | 479 South Way Dr | | | age | 43 | | | connections | | | 2 | | | 3 | | | 1 | | | 4 | | | expenses | | | books | 210 | | | food | 1100 | | | travel | 50 | | | firstname | Wendy | | | income | 80000 | | | lastLogin | 2017-07-25T22:50:06.482 | | | lastname | Purvis | +----+--------------------------------------------+

1 row returned

We can blindly update the value of the person.expenses.books field by referencing $.In the following statement, no read is performed on the store. Instead, the writeoperation is performed directly at the store.

sql-> UPDATE JSONPersons j -> SET j.person.expenses.books = $ + 100

Chapter 7Modifying Table Rows using UPDATE Statements

7-23

Page 97: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

-> WHERE id = 6; +----------------+ | NumRowsUpdated | +----------------+ | 1 | +----------------+

1 row returned

To see that the books expenses value has indeed been incremented by 100, weperform a second SELECT statement.

sql-> SELECT * FROM JSONPersons WHERE id=6; +----+--------------------------------------------+ | id | person | +----+--------------------------------------------+ | 6 | address | | | city | St. Petersburg | | | phones | | | areacode | 727 | | | number | 8284321 | | | type | work | | | | | | areacode | 727 | | | number | 5710076 | | | type | home | | | | | | areacode | 727 | | | number | 8913080 | | | type | mobile | | | state | FL | | | street | 479 South Way Dr | | | age | 43 | | | connections | | | 2 | | | 3 | | | 1 | | | 4 | | | expenses | | | books | 310 | | | food | 1100 | | | travel | 50 | | | firstname | Wendy | | | income | 80000 | | | lastLogin | 2017-07-25T22:50:06.482 | | | lastname | Purvis | +----+--------------------------------------------+

1 row returned

Chapter 7Modifying Table Rows using UPDATE Statements

7-24

Page 98: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Part IILanguage Definition

This part provides a textual overview of SQL for Oracle NoSQL Database. While someexamples are provided to illustrate concepts, more thorough examples are provided in Introductory Examples.

Page 99: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

8The SQL for Oracle NoSQL Database DataModel

This chapter gives an overview of the data model for SQL for Oracle NoSQLDatabase. For a more detailed description of the data model see the SQL for OracleNoSQL Database Specification.

Example DataThe language definition portion of this document frequently provides examples toillustrate the concepts. The following table definition is used by those examples:

CREATE TABLE Users ( id INTEGER, firstName STRING, lastName STRING, otherNames ARRAY(RECORD(first STRING, last STRING)), age INTEGER, income INTEGER, address JSON, connections ARRAY(INTEGER), expenses MAP(INTEGER), moveDate timestamp(4), PRIMARY KEY (id))

The rows of the Users table defined above represent information about users. Foreach such user, the “connections” field is an array containing ids of other users thatthis user is connected with. The ids in the array are sorted by some measure of thestrength of the connection.

The “expenses” column is a maps expense categories (like “housing”, clothes”,“books”, etc) to the amount spent in the associated category. The set of categoriesmay not be known in advance, or it may differ significantly from user to user, or mayneed to be frequently updated by adding or removing categories for each user. As aresult, using a map type for “expenses”, instead of a record type, is the right choice.

Finally, the “address” column has type JSON. A typical value for “address” will be amap representing a json document.

Typical row data for this table will look like this:

{ "id":1, "firstname":"David", "lastname":"Morrison", "otherNames" : [{"first" : "Dave", "last" : "Morrison"}],

8-1

Page 100: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

"age":25, "income":100000, "address":{"street":"150 Route 2", "city":"Antioch", "state":"TN", "zipcode" : 37013, "phones":[{"type":"home", "areacode":423, "number":8634379}] }, "connections":[2, 3], "expenses":{"food":1000, "gas":180}, "moveDate" : "2016-10-29T18:43:59.8319"}

Data Types and ValuesIn SQL for Oracle NoSQL Database data is modeled as typed items. A typed item (orsimply item) is a value and an associated type that contains the value. A type is adefinition of a set of values that are said to belong to (or be instances of) that type.

Values can be atomic or complex. An atomic value is a single, indivisible unit of data.A complex value is a value that contains or consists of other values and providesaccess to its nested values. Similarly, the types supported by SQL for Oracle NoSQLDatabase can be characterized as atomic types (containing atomic values only) orcomplex types (containing complex values only).

The data model supports the following kinds of atomic values and associated datatypes:

• Integer

4-byte long integer number.

• Long

8-byte long integer number.

• Float

4-byte long real number.

• Double

8-byte long real number.

• Number

All numbers that can be represented by the Java BigDecimal data type.

• String

Sequence of unicode characters.

• Boolean

Values are either true or false.

• Binaries

An uninterpreted sequence of zero or more bytes.

• Enums

Chapter 8Data Types and Values

8-2

Page 101: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Values are symbolic identifiers (tokens). Enums are stored as strings, but are notconsidered to be strings.

• Timestamp

Represents a point in time as a date and, optionally, a time. See Timestamp fordetails.

• JSON null value

Special value that indicates the absence of an actual value within a JSONdatatype such as an object, map, or array.

• SQL NULL

Special value that is used to indicate the absence of an actual value, or the factthat a value is unknown or inapplicable.

SQL for Oracle NoSQL Database also supports the following complex types:

• Array

An array is an ordered collection of zero or more items. Normally all elements ofan array have the same type. Also, normally arrays cannot contain NULL items.However, arrays of type JSON can contain a mix of JSON datatypes, as well asNULL items.

• Map

An unordered collection of zero or more key-item pairs, where all keys are stringsand all the items normally have the same type. Also, normally Maps cannotcontain NULL items. However, if the map is of type JSON, then it can contain amix of datatypes for the items, as well as NULL items.

• Record

An ordered collection of one or more key-item pairs, where all keys are strings andthe items associated with different keys may have different types. Also, recorditems may be NULL.

Another difference between records and maps is that the keys in records are fixed andknown in advance (they are part of the record type definition), whereas maps cancontain arbitrary keys (the map keys are not part of the map type).

Wildcard Types and JSON DataThe Oracle NoSQL data model includes the following wildcard types:

• Any

All possible values.

• AnyAtomic

All possible atomic values.

• AnyJsonAtomic

All atomic values that are valid JSON values. This is the union of all numericvalues, all string values, the 2 boolean values, and the JNULL value.

• JSON

All possible JSON values. The domain set is defined recursively as follows:

Chapter 8Wildcard Types and JSON Data

8-3

Page 102: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

1. All AnyJsonAtomic values.

2. All arrays whose elements are included in AnyJsonAtomic values.

3. All maps whose field values are those described in (1) and (2) of this list.

• AnyRecord

All possible record values.

With the exception of JNULL items (which pair the JNULL value with the JSON type),no item can have a wildcard type as its type. Wildcard types should be viewed asabstract types. However, items may have an imprecise type. For example, an itemmay have Map(JSON) as its type, indicating that its value is a map that can store fieldvalues of different types, as long as all of these values belong to the JSON type. Infact, Map(JSON) is the type that represents all JSON objects (JSON documents), andArray(JSON) is the type that represents all JSON arrays.

Note:

A type is called precise if it is not one of the wildcard types and, in case ofcomplex types, all of its constituent types are also precise. Items that haveprecise types are said to be strongly typed.

JSON DataTo load JSON data into a table, input is accepted as strings or streams containingJSON text. Oracle NoSQL Database parses the input text internally and maps itsconstituent pieces to the values and types of the data model described here.

Specifically, when an array is encountered in the input text, an array item is createdwhose type is Array(JSON). This is done unconditionally, no matter what the actualcontents of the array might be. For example, even if the array contains integers only,the array item that will be created will have type Array(JSON). The reason that thearray is not created with type Array(Integer) is that this would mean that we couldnever update the array by putting something other than integers.

For the same reason, when a JSON object is encountered in the input text, a map itemis created whose type is Map(JSON), unconditionally. When numbers are encountered,they are converted to integer, long, or double items, depending on the actual value ofthe number (float items are not used for JSON). Finally, strings in the input text aremapped to string items, boolean values are mapped to boolean items, and JSON nullsto JSON null items.

TimestampRepresents a point in time as a date and, optionally, a time value.

Timestamp values have a precision in fractional seconds that range from 0 to 9. Forexample, a precision of 0 means that no fractional seconds are stored, 3 means thatthe timestamp stores milliseconds, and 9 means a precision of nanoseconds. 0 is theminimum precision, and 9 is the maximum.

Chapter 8JSON Data

8-4

Page 103: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

There is no timezone information stored in timestamp; they are all assumed to be inthe UTC timezone.

The number of bytes used to store a timestamp depends on its precision (the on-diskstorage varies between 5 and 9 bytes).

This datatype is specified as a string in the following format:

"<yyyy>-<mm>-<dd>[T<HH>:<mm>:<ss>[.<SS>]]"

where:

• <yyyy> is the four-digit year value (for example, "2016").

• <mm> is the two-digit month value (for example, "08").

• <dd> is the two-digit day value (for example, "01").

• <HH> is the two-digit hour value (for example, "18").

• <mm> is the two-digit minute value.

<ss> is the two-digit seconds value.

• <SS> is the fractional seconds value. If the value specified here exceeds theprecision declared when the table column was defined, then the value specified isrounded off.

You can return the current time as a timestamp using the current_time() function.See Time Functions for details.

Timestamp FunctionsThe following functions can be used with the timestamp datatype:

• year(<timestamp>)

Returns the year for the given timestamp. The returned value is in the range -6383to 9999. If the <timestamp> argument is NULL or empty, the result is also NULL orempty.

• month(<timestamp>)

Returns the month for the given timestamp. The returned value is in the range 1 to12. If the <timestamp> argument is NULL or empty, the result is also NULL orempty.

• day(<timestamp>)

Returns the day for the given timestamp. The returned value is in the range 1 to31. If the <timestamp> argument is NULL or empty, the result is also NULL orempty.

• hour(<timestamp>)

Returns the hour for the given timestamp. The returned value is in the range 0 to23. If the <timestamp> argument is NULL or empty, the result is also NULL orempty.

• minute(<timestamp>)

Chapter 8Timestamp

8-5

Page 104: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Returns the minute for the given timestamp. The returned value is in the range 0 to59. If the <timestamp> argument is NULL or empty, the result is also NULL orempty.

• second(<timestamp>)

Returns the second for the given timestamp. The returned value is in the range 0to 59. If the <timestamp> argument is NULL or empty, the result is also NULL orempty.

• millisecond(<timestamp>)

Returns the millisecond for the given timestamp. The returned value is in the range0 to 999. If the <timestamp> argument is NULL or empty, the result is also NULLor empty.

• microsecond(<timestamp>)

Returns the microsecond for the given timestamp. The returned value is in therange 0 to 999999. If the <timestamp> argument is NULL or empty, the result isalso NULL or empty.

• nanosecond(<timestamp>)

Returns the nanosecond for the given timestamp. The returned value is in therange 0 to 999999999. If the <timestamp> argument is NULL or empty, the resultis also NULL or empty.

• week(<timestamp>)

Returns the week number within the year. Weeks start on a Sunday, and the firstweek in the year has a minimum of 1 day. The value returned is in the range 1 to54. If the argument is NULL or empty, the result is also NULL or empty.

• isoweek(<timestamp>)

Returns the week number within the year based on IS0-8601. Weeks start onMonday, and the first week has a minimum of 4 days. The value returned is in therange 0 to 53. If the argument is NULL or empty, the result is also NULL or empty.

• extract(<unit> from <expr>)

Extracts temporal fields from a timestamp field. <expr> must return a timestamp.<unit> must be one of YEAR, MONTH, DAY, HOUR, MINUTE, SECOND,MILLISECOND, MICROSECOND, NANOSECOND, WEEK, or ISOWEEK.

See Working with Timestamps for an example of using these functions.

Type HierarchySQL for Oracle NoSQL Database defines a subtype-supertype relationship among thetypes such that types are arranged in a hierarchy. For example, every type is asubtype of ANY. Any atomic type is a subtype of AnyAtomic. Integer is a subtype ofLong. An array is a subtype of JSON if its element type is JSON or another subtype ofJSON.

A data item is an instance of a type (T) if the data item's type is (T) or a subtype of (T).

This relationship is important because the usual subtype-substitution rule is supportedby SQL for Oracle NoSQL Database. If an operation expects input items of type (T), orproduces items of type (T), then it can also operate on or produce items of type (S) if

Chapter 8Type Hierarchy

8-6

Page 105: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

(S) is a subtype of (T). (There is an exception to this rule. See Subtype-SubstitutionRule Exceptions).

The following figure illustrates this data hierarchy. Dotted boxes in the figure representcollections of types.

In addition to the subtype relationships described here, the following relationships arealso defined:

• Every type is a subtype of itself. A type (T) is a proper subtype of another type (S)if (T) is a subtype of (S) and (T) is not equal to (S).

Chapter 8Type Hierarchy

8-7

Page 106: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

• An enum type is a subtype of another enum type if both types contain the sametokens and in the same order, in which case the types are actually consideredequal.

• Timestamp(p1) is a subtype of Timestamp(p2) if p1 <= p2.

• A record type (S) is a subtype of another record type (T) if:

1. both types contain the same field names in the same order; and

2. for each field, its value type in (s) is a subtype of its value type in (T); and

3. nullable fields in (S), are also nullable in (T).

• (Array(S)) is a subtype of (Array(T)) if (S) is a subtype of (T).

• (Map(S)) is a subtype of (Map(T)) if (S) is a subtype of (T).

Subtype-Substitution Rule ExceptionsOrdinarily, if an operation expects input items of type (T), or produces items of type(T), then it can also operate on or produce items of type (S) if (S) is a subtype of (T).However, there are two exceptions to this rule.

The first exception concerns numeric values. Double and Float are subtypes ofNumber. However, Double and Float include three special values: NaN (not anumber), positive infinity, and negative infinity. These values are not in the domain ofNumber. Therefore, an operation that expects a Number value will also work withDouble/Float values as long as these values are not one of the three special values. Ifone of the three special values are used with Number, and error is raised.

Secondly, items whose type is a proper subtype of Array(JSON) or Map(JSON) cannotbe used as:

• record/map field values if the field type is JSON, Array(JSON) or Map(JSON); or

• elements of arrays whose element type is JSON, Array(JSON) or Map(JSON).

This is in order to disallow strongly type data to be inserted into JSON data.

For example, consider a JSON document which is a map value whose associated typeis Map(JSON). The document may contain an array whose values contain onlyintegers. However, the type associated with the array cannot be Array(integer), it mustbe Array(JSON). If the array had type Array(integer), the user would not be able to addany non-integer values to it.

SQL for Oracle NoSQL Database SequencesA sequence is an important concept in SQL for Oracle NoSQL Database. It is usedwherever expressions and operators are discussed.

A sequence is the result of any expression that returns zero or more items. Sequencesare not containers; they cannot be nested.

Note that an array is not a sequence; rather it is a single item that contains other itemsin it.

Sequences have a type. A sequence type specifies the type of items that may appearin a sequence. For example, a sequence could contain atomic elements that are oftype integer. In this case, the sequence type would be integer.

Chapter 8SQL for Oracle NoSQL Database Sequences

8-8

Page 107: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Sequence types have a cardinality. The cardinality indicates constraints on how manyitems can or must appear in the sequence:

• *

indicates a sequence of zero or more items.

• +

indicates a sequence of one or more items.

• ?

indicates a sequence of zero or one items.

• The absence of a quantifier indicates a sequence of exactly one item.

When we say that the result of an expression must have a sequence of a certain type,what we mean is the sequence must have that type or any subtype of that type.

Sequence subtypes are defined as follows:

• The empty sequence is a subtype of all sequence types whose quantifier is * or ?.

• A sequence type (s1) is a subtype of another sequence type (s2) if:

– s1's item type is a subtype of s2's item type; and

– s1's sequence quantifier is a sub-quantifier for s2's quantifier.

The following table shows the subtype relationship for the various quantifiers:

Sequence Concatenation FunctionUse the any* seq_concat(<argument>*) to concatenate one sequence to anothersequence. This function evaluates its arguments (if any) in the order they are listed inthe arguments list, and concatenates the sequences returned by these arguments.

For an example of using this function, see Adding Elements to an Array.

Chapter 8SQL for Oracle NoSQL Database Sequences

8-9

Page 108: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

9SQL for Oracle NoSQL Database Queries

This chapter describes the Select-From-Where (SFW) expression, which is the coreexpression used to form SQL queries. For examples of using SFW expressions, seethese extended examples:

• Simple SELECT Queries

• Working with complex data

• Working With Indexes

• Working with JSON

For a more detailed description of the language see the SQL for Oracle NoSQLDatabase Specification.

Note:

The examples shown in this chapter rely on the sample data shown in Example Data.

Select-From-Where (SFW) ExpressionsA query is always a single Select-From-Where (SFW) expression. The SFWexpression is essentially a simplified version of the SQL Select-From-Where queryblock. The two most important simplifications are the lack of support for joins and forsubqueries. On the other hand, to manipulate complex data (records, arrays, andmaps), SQL for Oracle NoSQL Database provides extensions to traditional SQLthrough novel kinds of expressions, such as path expressions.

The semantics of the SFW expression are similar to those in standard SQL.Processing starts with the FROM clause, followed by the WHERE clause (if any),followed by the GROUP BY clause (if any), and finishing with the SELECT clause. Or,the processing starts with the FROM clause, followed by the WHERE clause (if any),followed by the ORDER BY clause (if any), followed by the OFFSET and LIMITclauses, and finishing with the SELECT clause. Each clause is described below. Aquery must contain exactly one SFW expression, which is also the top-levelexpression of the query. Subqueries are not supported yet.

SELECT <expression>FROM <table name>[WHERE <expression>][GROUP BY <expression>][ORDER BY <expression> [<sort order>]][OFFSET <number>][LIMIT <number>];

9-1

Page 109: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Each of the SFW clauses are introduced in the following sections. For details on eachclause, see the SQL for Oracle NoSQL Database Specification.

SELECT ClauseSELECT clauses come in two forms. In the first form, it contains only a single star (*)symbol. This form simply returns all rows.

SELECT * FROM Users;

In the second form, the SELECT clause contains a comma-separated list of fieldexpressions, where each expression is optionally associated with a name. In thesimplest case, each expression is simply the name of a column in the table from whichdata is being selected.

SELECT id, firstname, lastname FROM Users;

The AS keyword can also be used:

SELECT id, firstname AS Name, lastname AS Surname FROM Users;

SELECT clauses can contain many different kinds of expressions. For moreinformation, see Expressions.

The SELECT clause always returns a record. Normally, the record has one field foreach field expression, and the fields are arranged in the same order as the fieldexpressions. Each field value is the value computed by the corresponding fieldexpression and its name is the name associated with the field expression. If no fieldname is provided explicitly (using the AS keyword), one is automatically generated foryou.

To create valid records, the field names must be unique, and they must return at mostone item. If a field expression returns more than one result, the result is returned in anarray.

If the result of a field expression is empty, NULL is used as the value of thecorresponding field in the record returned by SELECT.

Note:

If the SELECT clause contains only one field expression with no associatedname, then just the value returned by the clause is returned. If this value isalready a record, then this is returned. If this value is not a record, then it iswrapped in a record before being returned.

Chapter 9Select-From-Where (SFW) Expressions

9-2

Page 110: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

SELECT Clause HintsThe SELECT clause can contain one or more hints which are used to help choose anindex to use for the query. A hint is a comment that begin with a + symbol:

/*+ <hint> */

Each hint takes the form:

<hint type> (<table path> [<index name>]) [comment string]

The following hint types are supported:

• FORCE_INDEX

Specifies a single index, which is used without considering any of other indexes.This is true even if there are no index predicates for the forced index. However, ifthe query has an ORDER BY clause, and the forced index is not the sorting index,an error is thrown.

This index hint requires you to specify an <index name>.

• PREFER_INDEXES

The PREFER_INDEXES hint specifies one or more indexes. The query processormay or may not use one of the preferred indexes.

This index hint requires you to specify at least one <index name>.

• FORCE_PRIMARY_INDEX

Requires the query to use the table's primary index.

You do not specify an <index name> when you use this type of hint.

• PREFER_PRIMARY_INDEX

Specifies that you prefer to use the primary index for the query. This index may ormay not be used.

You do not specify an <index name> when you use this type of hint.

For more information on indexes, see Working With Indexes.

FROM ClauseThe FROM clause is very simple: it can include only a single table. The table isspecified by its name, which may be a composite (dot-separated) name in the case ofchild tables. The table name may be followed by a table alias.

For example, to select a table named Users:

<select expression> FROM Users <other clauses>;

To select a table named People, which is a child of a table named Organizations:

<select expression> FROM Organizations.People <other clauses>;

Chapter 9Select-From-Where (SFW) Expressions

9-3

Page 111: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

To select a table named People and give it the alias u:

<select expression> FROM Users u <other clauses>;

The result of the FROM clause is a sequence containing the rows of the referencedtable. The FROM clause creates a nested scope, which exists for the rest of the SFWexpression.

The SELECT, WHERE, and ORDER BY clauses operate on the rows produced by theFROM clause, processing one row at a time. The row currently being processed iscalled the context row. The context row can be referenced in expressions by either thetable name, or the table alias.

If the table alias starts with a dollar sign ($), then it serves as a variable declarationwhose name is the alias. This variable is bound to the context row and can bereferenced within the SFW expression anywhere an expression returning a singlerecord may be used. If this variable has the same name as an external variable, ithides the external variable. Because table alias are essentially variables, the like allother variables their names are case-sensitive.

WHERE ClauseThe WHERE clause returns a subset of the rows coming from the FROM clause.Specifically, for each context row, the expression in the WHERE clause is evaluated.The result of this expression must have type BOOLEAN?. If the result is false, orempty, or NULL, the row is skipped; otherwise the row is passed on to the next clause.

For example, to limit the rows selected to just those where the column firstnamecontains John:

<select statement> <from statement> WHERE firstname = "John";

GROUP BY ClauseA GROUP BY clause groups the results of a SELECT statement by one or more tablecolumns. The GROUP BY clause partitions it’s input sequence of rows into groups,where all the rows in the same group have equal values for the grouping expressionand each grouping expression will return at most one atomic value.

If the grouping expression returns an empty result on an input row, that row is skipped.Equality among grouping values is defined according the semantics of the “=”operator, with an exception that two NULL values are considered equal. Then, foreach group, a single record is constructed and returned by the GROUP BY clause.

You typically use a GROUP BY clause in conjunction with an aggregate expression.For example, to get a count of the number of users by age.

SELECT COUNT(id), age FROM Users GROUP BY age;

Syntactically, aggregate functions are listed in the SELECT clause and not theGROUP BY clause, and they cannot be nested. Semantically however, everyaggregate function that appears in the SELECT list is actually evaluated by theGROUP BY clause. If the SELECT clause contains any aggregate functions and theSelect-From-Where (SFW) expression does not contain a GROUP BY clause, the

Chapter 9Select-From-Where (SFW) Expressions

9-4

Page 112: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

whole set of rows produced by the FROM and the WHERE clause is considered as asingle group and the aggregate functions are evaluated over this group.

Remember that grouping is only possible if there exists an index that sorts the rows bythe grouping expression. As we will see in the later sections, a similar restriction existsfor the ORDER BY clause. Therefore, it is not currently possible to have both aGROUP BY and an ORDER BY clause in the same SFW expression. On the otherhand, since grouping is implemented based on index ordering, the results of agrouping SFW will be ordered by the grouping expressions.

Aggregate FunctionsAggregate functions return a single result based on groups of rows, rather than onsingle rows.

Aggregate functions are commonly used with the GROUP BY clause in a SELECTstatement, where they are divided into the rows of a queried table and viewed asgroups. Aggregate functions are applied to each group of rows, and return a singleresult for each group.

• long count(*)

The count(*) function returns the number of rows in a group.

• long count(any*)

The count function computes its input expression on each row in a group andreturns a count of all the non-NULL values of the input expression, for each group.

• number sum(any*)

The sum function computes its input expression on each row in a group andreturns the sum of values of the expression for each group. The resulting valuehas type long, double, or number, depending on the type of the input items: if thereis at least one input item of type number, the result will be a number, otherwise ifthere is at least one item of type double or float, the result will be double,otherwise the result will be a long. If the input item is non-numeric, the row isskipped.

• number avg(any*)

The avg (average) function computes its input expression on each row in a groupand returns the count of the number of rows in each group, as well as the sum ofvalues of the expression for each group. The resulting value is the division of thesum by the count. This value has type double, or number, depending on the typeof the input items: if there is at least one input item of type number, the result willbe a number, otherwise the result will be double. If the input item is non-numeric,the row is skipped.

• any_atomic min(any*)

The min (minimum) function computes its input expression on each row in a groupand returns the minimum value of the expression for each group.

For detailed information on how the minimum value for each group is calculated,refer to the Aggregate Functions topic in the SQL for Oracle NoSQL DatabaseSpecification guide.

• any_atomic max(any*)

The max (maximum) function computes its input expression on each row in agroup and returns the maximum value of the expression for each group.

Chapter 9Select-From-Where (SFW) Expressions

9-5

Page 113: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

For detailed information on how the maximum value for each group is calculated,refer to the Aggregate Functions topic in the SQL for Oracle NoSQL DatabaseSpecification guide.

The above functions are called the SQL aggregate functions, because theirsemantics are similar to those in standard SQL; they work in conjunction with groupingand they aggregate values across the rows of a group. However, what if you just wantto aggregate the values of an array or map inside the context row, without anygrouping across rows? To this end, Oracle NoSQL Database provides, for each SQLaggregate function, a corresponding sequence aggregate function. Specifically, thefollowing functions are available:

• long seq_count(any*)

• number seq_sum(any*)

• number seq_avg(any*)

• any_atomic seq_min(any*)

• any_atomic seq_max(any*)

These functions simply aggregate the items in their input sequence, using the samerules as their corresponding SQL aggregate function. For example, seq_sum() skipsany non-numeric items in the input sequence and determines the actual type of thereturn value (long, double, or number), the same way as the SQL sum(). The onlyexception is seq_count(), which in contrary to the SQL count(), includes NULLs inthe count. An example using seq_sum() and seq_max() is shown in section 4.4.4 of theSQL for Oracle NoSQL Database Specification.

Examples

Aggregate functions are further explained with examples. The following script createsthe Employees table.

CREATE TABLE Employees( id integer, firstname string, lastname string, job string, age integer, salary integer, department string, primary key (id));

Let us assume the Employees table contains the following data:

sql-> SELECT * FROM Employees; +----------------+-----------+------------+-----+--------+-----------+ | id | firstname | lastname | job | age | salary | department| +----------------+-----------+------------+-----+--------+-----------+ | 1 | Hannah | Simpson | Manager | 35 | 300000 | Finance | | 2 | Sheela | Menon | Clerk | 26 | 100000 | Finance | | 3 | Alex | Vausse | Accountant | 28 | 100000 | Accounts | | 4 | Piper | Chapman | Accountant | 30 | 150000 | Accounts | | 5 | Vicky | Lincoln | Clerk | 35 | 165000 | Finance | | 6 | Thomos | Hardy | Manager | 33 | 350000 | Accounts |

Chapter 9Select-From-Where (SFW) Expressions

9-6

Page 114: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| 7 | Shawn | Wilson | Accuntant | 35 | 165000 | Accounts | | 8 | Steve | Moos | Manager | 32 | 300000 | HR | | 9 | Keith | Simpson | HR_Rep | 35 | 300000 | HR | -----+-----------+-----------+------------+-----+--------+-----------+

9 rows returned

Execute the following SQL statement to return the maximum salary of employeesbased on their job:

sql-> SELECT firstname, job, MAX(salary) FROM Employees GROUP BY job; +-----------+--------------+-------------+ | firstname | job | MAX(salary)| +-----------+--------------+-------------+ | Shawn | Acccountant | 165000 | | Vicky | Clerk | 165000 | | Keith | HR_Rep | 300000 | | Thomos | Manager | 350000 | +-----------+--------------+-------------+

4 rows returned

Execute the following SQL statement to return the count of employees working in eachdepartment:

sql-> SELECT department, COUNT(id) FROM Employees GROUP BY department; +------------+------------+ | department | COUNT(id) | +------------+------------+ | Accounts | 4 | | Finance | 3 | | HR | 2 | +------------+------------+

3 rows returned

You can also use multiple grouping columns in the SELECT statement. For example,execute the following SQL statement to return the total salary of employees for eachjob role, in each department:

sql-> SELECT department, job, SUM(salary) FROM Employees GROUP BY department, job; +------------+-------------+-------------+ | department | job | SUM(salary) | +------------+-------------+-------------+ | Accounts | Accountant | 415000 | | Accounts | Manager | 350000 | | Finance | Clerk | 265000 | | Finance | Manager | 300000 | | HR | HR_Rep | 300000 | | HR | Manager | 300000 | +------------+-------------+-------------+

Chapter 9Select-From-Where (SFW) Expressions

9-7

Page 115: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

6 rows returned

ORDER BY ClauseThe ORDER BY clause reorders the sequence of rows it receives as input. Therelative order between any two input rows is determined by evaluating, for each row,the expressions listed in the order-by clause and comparing the resulting values. Eachorder-by expression must have type AnyAtomic?.

Note:

It is possible to perform ordering only if there is an index that already sortsthe rows in the desired order.

For detailed information on how comparison is performed for order-by expressions,see the SQL for Oracle NoSQL Database Specification.

For example, to order a query result by age.

<select statement> <from statement> WHERE firstname = "John" ORDER BY age;

It is possible to specify a sorting order: ASC (ascending) or DESC (descending).Ascending is the default sorting order. To present these results in descending order:

<select statement> <from statement> WHERE firstname = "John" ORDER BY age DESC;

You can also specify whether NULLS should come first or last in the sorting order. Forexample:

<select statement> <from statement> WHERE firstname = "John" ORDER BY age DESC NULLS FIRST;

Remember that ordering is only possible if there is an index that sorts the rows in thedesired order. Be aware that, in the current implementation, NULLs are always sortedlast in the index.

The specified handling for NULLs must match the index so, currently, if the sort orderis ascending then NULL LAST must be used, and if the sort order is descending thenNULL FIRST must be used.

Comparison RulesThis section describes the sorting rules used when query results are sorted.

First, consider the case where only one ORDER BY clause is used in the query.

Chapter 9Select-From-Where (SFW) Expressions

9-8

Page 116: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Two rows are considered equal if both rows contain the same number of elements,and for equivalent positions in each row, the atomic values are identical. So if youhave two rows, R1 and R2, then they are equal if R1[0] = R2[0] and R1[1] = R1[1]. Inthis context, NULLs are considered equal only to other NULLs.

Assuming that the number of elements in R1 and R2 are equal, then R1 is less thanR2 if any of the following is true:

• No NULLs appear in either row and sorting is in ascending order. In this case, R1is less than R2 if there are a positionally-equivalent pair of atomic elements (asevaluated from lowest to highest) where the R1 element is less than the R2element. That is, if R1[1] < R2[2] then R1 is less than R2.

• No NULLs appear in either row and sorting is in descending order. In this case, R1is less than R2 if there are a positionally-equivalent pair of atomic elements (asevaluated from lowest to highest) where the R1 element is greater than the R2element. That is, if R1[1] > R2[2] then R1 is less than R2.

• A NULL appears in R2, but not in R1, and sorting is in ascending order withNULLS LAST.

• A NULL appears in R2, but not in R1, and sorting is in descending order withNULLS FIRST.

If multiple ORDER BY statements are offered, then atomic values are returned forcomparison purposes by evaluating the statements from left to right.

Be aware that if an expression returns an empty sequence, then the return value isNULL.

If no sorting order is provided to the query, then by default ascending order withNULLS LAST is used. If only the sort order is specified, then NULLs sort last if theorder is ascending. Otherwise, they sort first.

OFFSET ClauseSpecifies the number of initial query results that should be skipped; that is, they arenot returned. This clause accepts a single non-negative integer as its argument. Thisargument may be a single integer literal, or a single external variable, or anyexpression which is built from literals and external variables.

Although it is possible to use this clause without an ORDER BY clause, it does notmake sense to do so. Without an ORDER BY clause, results are returned in randomorder, so the subset of results skipped will be different each time the query is run.

LIMIT ClauseSpecifies the maximum number of results to return. This clause accepts a single non-negative integer as its argument. This argument may be a single integer literal, or asingle external variable, or any expression which is built from literals and externalvariables.

Although it is possible to use this clause without an ORDER BY clause, it does notmake sense to do so. Without an ORDER BY clause, results are returned in randomorder, so the subset of results returned will be different each time the query is run.

Chapter 9OFFSET Clause

9-9

Page 117: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

JoinsOracle NoSQL Database supports joins among tables in the same hierarchy. Thesejoins are executed efficiently as only co-located rows match with each other, henceavoiding large amounts of data transfer among servers.

To query multiple tables in the same hierarchy, the NESTED TABLES clause must beused inside the FROM clause.

SELECT <expression 1>, <expression 2>, ... <expression n>FROM NESTED TABLES( <table name> [(ANCESTORS <table 1> [ON <expression 1>], <table 2> [ON <expression 2>], ... <table n> [ON <expression n>])] [(DESCENDANTS <table 1> [ON <expression 1>], <table 2> [ON <expression 2>], ... <table n> [ON <expression n>])])[WHERE <expression>][GROUP BY <column name>][ORDER BY <column name> [<sort order>]][OFFSET <number>][LIMIT <number>];

NESTED TABLES ClauseThe NESTED TABLES clause specifies the participating tables and separates them inthe following groups:

1. Target table — Specifies the table where the action must take place.

2. ANCESTORS clause — Specifies a number of tables that must be ancestors ofthe target table in the table hierarchy.

3. DESCENDANTS clause — Specifies a number of tables that must bedescendants of the target table in the table hierarchy.

A unique alias can be specified for each table. If not specified, an alias is createdinternally by using the table name.

A NESTED TABLES clause produces a set of records, all having the same type,where:

• The number of fields is equal to the number of participating tables

• Each field corresponds to a table and stores either a row from that table or NULL

• The name of each field is the alias used by the associated table

• The fields are ordered in the way that the participating tables would beencountered in a depth-first traversal of the table hierarchy

Semantically, a NESTED TABLES clause is equivalent to a number of left-outer joinoperations “centered” around the target table. Left-outer join is an operation defined instandard SQL. In comparison to standard SQL, NoSQL has a slight difference in the“shape” of the results. The standard left-outer join in SQL produces a “flat” resultwhere each result is a record/tuple. The number of fields in each result is the sum ofall the columns in the participating tables. However, in NoSQL, in each result of the

Chapter 9Joins

9-10

Page 118: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

NESTED TABLES clause the columns from each table are grouped inside asubrecord.

The NESTED TABLES clause is further explained with examples. The following scriptcreates four tables:

CREATE TABLE customers ( customer_id INTEGER, name STRING, home_phone STRING, office_phone STRING, PRIMARY KEY (customer_id));CREATE TABLE customers.addresses ( address_id INTEGER, street STRING, city STRING, state STRING, address_type STRING, PRIMARY KEY (address_id));CREATE TABLE customers.invoices ( invoice_no INTEGER, time TIMESTAMP(3), PRIMARY KEY (invoice_no));CREATE TABLE customers.invoices.items ( item_no INTEGER, qty INTEGER, price FLOAT, PRIMARY KEY (item_no));

ExamplesFor the following examples, let’s assume that the following tables created in theprevious section contain the following data:

sql-> mode column;Query output mode is COLUMNsql-> SELECT * FROM customers; +-------------+-------+------------+--------------+ | customer_id | name | home_phone | office_phone | +-------------+-------+------------+--------------+ | 2 | Boris | 2222222 | 2222223 | | 3 | Cathy | 3333333 | 3333334 | | 1 | Adam | 1111111 | 1111112 | +-------------+-------+------------+--------------+

3 rows returnedsql-> SELECT * FROM customers.addresses; +-------------+------------+--------------+--------+---------------+--------------+ | customer_id | address_id | street | city | state |

Chapter 9Joins

9-11

Page 119: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

address_type | +-------------+------------+--------------+--------+---------------+--------------+ | 2 | 2 | Boris Street | Denver | Colorado | Home | | 1 | 1 | Adam Street | Boston | Massachusetts | Home | +-------------+------------+--------------+--------+---------------+--------------+

2 rows returnedsql-> SELECT * FROM customers.invoices; +-------------+------------+-------------------------+ | customer_id | invoice_no | time | +-------------+------------+-------------------------+ | 2 | 2 | 2018-03-02T11:18:16.000 | | 1 | 3 | 2018-03-02T11:29:19.000 | | 1 | 4 | 2018-03-02T11:33:13.000 | +-------------+------------+-------------------------+

3 rows returnedsql-> SELECT * FROM customers.invoices.items; +-------------+------------+---------+-----+-------+ | customer_id | invoice_no | item_no | qty | price | +-------------+------------+---------+-----+-------+ | 2 | 2 | 3 | 1 | 14.99 | | 2 | 2 | 4 | 2 | 10.0 | | 1 | 3 | 5 | 2 | 13.32 | | 1 | 3 | 6 | 2 | 20.0 | | 1 | 4 | 7 | 1 | 22.23 | +-------------+------------+---------+-----+-------+

5 rows returned

Example 1

sql-> mode lineQuery output mode is LINEsql-> SELECT * FROM NESTED TABLES (customers.invoices.items itemsANCESTORS(customers, customers.invoices invoices) );

> Row 0 +-----------+----------------------------------------+ | customers | customer_id | 2 | | | name | Boris | | | home_phone | 2222222 | | | office_phone | 2222223 | +-----------+----------------------------------------+ | invoices | customer_id | 2 | | | invoice_no | 2 | | | time | 2018-03-02T11:18:16.000 | +-----------+----------------------------------------+

Chapter 9Joins

9-12

Page 120: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| items | customer_id | 2 | | | invoice_no | 2 | | | item_no | 3 | | | qty | 1 | | | price | 14.99 | +-----------+----------------------------------------+

> Row 1 +-----------+----------------------------------------+ | customers | customer_id | 2 | | | name | Boris | | | home_phone | 2222222 | | | office_phone | 2222223 | +-----------+----------------------------------------+ | invoices | customer_id | 2 | | | invoice_no | 2 | | | time | 2018-03-02T11:18:16.000 | +-----------+----------------------------------------+ | items | customer_id | 2 | | | invoice_no | 2 | | | item_no | 4 | | | qty | 2 | | | price | 10.0 | +-----------+----------------------------------------+--More--(1~2) <Press enter>

> Row 2 +-----------+----------------------------------------+ | customers | customer_id | 1 | | | name | Adam | | | home_phone | 1111111 | | | office_phone | 1111112 | +-----------+----------------------------------------+ | invoices | customer_id | 1 | | | invoice_no | 3 | | | time | 2018-03-02T11:29:19.000 | +-----------+----------------------------------------+ | items | customer_id | 1 | | | invoice_no | 3 | | | item_no | 5 | | | qty | 2 | | | price | 13.32 | +-----------+----------------------------------------+

> Row 3 +-----------+----------------------------------------+ | customers | customer_id | 1 | | | name | Adam | | | home_phone | 1111111 | | | office_phone | 1111112 | +-----------+----------------------------------------+ | invoices | customer_id | 1 | | | invoice_no | 3 | | | time | 2018-03-02T11:29:19.000 |

Chapter 9Joins

9-13

Page 121: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

+-----------+----------------------------------------+ | items | customer_id | 1 | | | invoice_no | 3 | | | item_no | 6 | | | qty | 2 | | | price | 20.0 | +-----------+----------------------------------------+--More--(3~4) <Press enter>

> Row 4 +-----------+----------------------------------------+ | customers | customer_id | 1 | | | name | Adam | | | home_phone | 1111111 | | | office_phone | 1111112 | +-----------+----------------------------------------+ | invoices | customer_id | 1 | | | invoice_no | 4 | | | time | 2018-03-02T11:33:13.000 | +-----------+----------------------------------------+ | items | customer_id | 1 | | | invoice_no | 4 | | | item_no | 7 | | | qty | 1 | | | price | 22.23 | +-----------+----------------------------------------+

5 rows returned

In this example, the NESTED TABLES clause includes ANCESTORS only.Specifically, the target table is customers.invoices.items and the ANCESTORStables are customers and customers.invoices.

As each target table row has at most one matching row from the ancestor tables, thisoperation selects the target table rows and the matching ancestor rows. No rows areeliminated or added. As a result, the count of records in the result set is always thesame as the number of target table rows.

Note:

Implicitly, the predicates for all join operations are on the primary keycolumns of the participating tables.

Example 2

sql-> mode columnsql-> SELECT a.customer_id, name, b.invoice_no, item_no, qty, priceFROM NESTED TABLES (customers aDESCENDANTS(customers.invoices b, customers.invoices.items c)); +-------------+-------+------------+---------+------+-------+

Chapter 9Joins

9-14

Page 122: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| customer_id | name | invoice_no | item_no | qty | price | +-------------+-------+------------+---------+------+-------+ | 2 | Boris | 2 | 3 | 1 | 14.99 | | 2 | Boris | 2 | 4 | 2 | 10.0 | | 3 | Cathy | NULL | NULL | NULL | NULL | | 1 | Adam | 3 | 5 | 2 | 13.32 | | 1 | Adam | 3 | 6 | 2 | 20.0 | | 1 | Adam | 4 | 7 | 1 | 22.23 | +-------------+-------+------------+---------+------+-------+

6 rows returned

In this NESTED TABLES clause, the target table is customers and theDESCENDANTS tables are customers.invoices.items and customers.invoices.

This operation selects all rows from the customers table. Each row is then joined withthe matching rows from the customers.invoices table. Each row is then further joinedwith the matching rows from the customers.invoices.items table. For customersrows that don’t have any matching customers.invoices rows, it displays NULL for allthe column in the customers.invoices table and customers.invoices.items table.

Example 3

sql-> SELECT a.customer_id, name, city, invoice_no, timeFROM NESTED TABLES (customers aDESCENDANTS (customers.addresses, customers.invoices)); +-------------+-------+--------+------------+-------------------------+ | customer_id | name | city | invoice_no | time | +-------------+-------+--------+------------+-------------------------+ | 2 | Boris | Denver | NULL | NULL | | 3 | Cathy | NULL | NULL | NULL | | 1 | Adam | Boston | NULL | NULL | | 2 | Boris | NULL | 2 | 2018-03-02T11:18:16.000 | | 1 | Adam | NULL | 3 | 2018-03-02T11:29:19.000 | | 1 | Adam | NULL | 4 | 2018-03-02T11:33:13.000 | +-------------+-------+--------+------------+-------------------------+

6 rows returned

In this NESTED TABLES clause, the target table is customers and theDESCENDANTS tables are customers.addresses and customers.invoices.

Like the previous example, this NESTED TABLES clause also includesDESCENDANTS only. However, in this NESTED TABLES clause, the descendanttables come from two different branches of the table hierarchy. In such scenario, theresult is a combination of join and union of the rows.

Chapter 9Joins

9-15

Page 123: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

First, a union is performed on the customers.addresses and customers.invoicestables, producing the following intermediate result (the result shows only the columnsparticipating in this query):

+-------------+--------+------------+-------------------------+ | customer_id | city | invoice_no | time | +-------------+--------+------------+-------------------------+ | 2 | Denver | NULL | NULL | | 1 | Boston | NULL | NULL | | 2 | NULL | 2 | 2018-03-02T11:18:16.000 | | 1 | NULL | 3 | 2018-03-02T11:29:19.000 | | 1 | NULL | 4 | 2018-03-02T11:33:13.000 | +-------------+--------+------------+-------------------------+

Then, the customers table is joined with the intermediate result producing the finalresult (as shown in the example).

Example 4

sql-> SELECT a.customer_id, name, city, c.invoice_no, item_no, qty, priceFROM NESTED TABLES (customers aDESCENDANTS (customers.addresses b, customers.invoices c, customers.invoices.items d)); +-------------+-------+--------+------------+---------+------+-------+ | customer_id | name | city | invoice_no | item_no | qty | price | +-------------+-------+--------+------------+---------+------+-------+ | 2 | Boris | Denver | NULL | NULL | NULL | NULL | | 2 | Boris | NULL | 2 | 3 | 1 | 14.99 | | 2 | Boris | NULL | 2 | 4 | 2 | 10.0 | | 3 | Cathy | NULL | NULL | NULL | NULL | NULL | | 1 | Adam | Boston | NULL | NULL | NULL | NULL | | 1 | Adam | NULL | 3 | 5 | 2 | 13.32 | | 1 | Adam | NULL | 3 | 6 | 2 | 20.0 | | 1 | Adam | NULL | 4 | 7 | 1 | 22.23 | +-------------+-------+--------+------------+---------+------+-------+

8 rows returned

This example is another variant of the previous example.

Example 5

In this example, you see the difference between the WHERE and ON predicates.

First, you run a query with no predicates at all:

sql-> SELECT b.customer_id, name, a.invoice_no, time, item_no, qtyFROM NESTED TABLES (customers.invoices aANCESTORS (customers b)DESCENDANTS (customers.invoices.items c));

Chapter 9Joins

9-16

Page 124: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

+-------------+-------+------------+-------------------------+---------+-----+ | customer_id | name | invoice_no | time | item_no | qty | +-------------+-------+------------+-------------------------+---------+-----+ | 1 | Adam | 3 | 2018-03-02T11:29:19.000 | 5 | 2 | | 1 | Adam | 3 | 2018-03-02T11:29:19.000 | 6 | 2 | | 1 | Adam | 4 | 2018-03-02T11:33:13.000 | 7 | 1 | | 2 | Boris | 2 | 2018-03-02T11:18:16.000 | 3 | 1 | | 2 | Boris | 2 | 2018-03-02T11:18:16.000 | 4 | 2 | +-------------+-------+------------+-------------------------+---------+-----+

5 rows returned

Then, you run a query with WHERE predicate on qty.

sql-> SELECT b.customer_id, name, a.invoice_no, time, item_no, qtyFROM NESTED TABLES (customers.invoices aANCESTORS (customers b)DESCENDANTS (customers.invoices.items c))WHERE c.qty = 2; +-------------+-------+------------+-------------------------+---------+-----+ | customer_id | name | invoice_no | time | item_no | qty | +-------------+-------+------------+-------------------------+---------+-----+ | 2 | Boris | 2 | 2018-03-02T11:18:16.000 | 4 | 2 | | 1 | Adam | 3 | 2018-03-02T11:29:19.000 | 5 | 2 | | 1 | Adam | 3 | 2018-03-02T11:29:19.000 | 6 | 2 | +-------------+-------+------------+-------------------------+---------+-----+

3 rows returned

The third and fourth rows are eliminated due to the WHERE predicate.

Next, you run the query with the same qty predicate but this time appearing as an ONpredicate.

sql-> SELECT b.customer_id, name, a.invoice_no, time, item_no, qtyFROM NESTED TABLES (

Chapter 9Joins

9-17

Page 125: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

customers.invoices aANCESTORS (customers b)DESCENDANTS (customers.invoices.items c ON qty = 2)); +-------------+-------+------------+-------------------------+---------+------+ | customer_id | name | invoice_no | time | item_no | qty | +-------------+-------+------------+-------------------------+---------+------+ | 2 | Boris | 2 | 2018-03-02T11:18:16.000 | 4 | 2 | | 1 | Adam | 3 | 2018-03-02T11:29:19.000 | 5 | 2 | | 1 | Adam | 3 | 2018-03-02T11:29:19.000 | 6 | 2 | | 1 | Adam | 4 | 2018-03-02T11:33:13.000 | NULL | NULL | +-------------+-------+------------+-------------------------+---------+------+

4 rows returned

Notice that the result returns NULL from the customers.invoices.items table forinvoice no 4.

In a left-outer join operation, each row from the customers.invoices table mustappear at least once in the result set. In this example, the last row appears once, butthe corresponding row from the customers.invoices.items table (item no 7) returnsNULL. The qty of item no 7 doesn’t fulfill the ON predicate expression (qty = 2) andbecause each row from the customers.invoices table has to be displayed at leastonce, it returns NULL.

Apart from a few restrictions, the NESTED TABLES clause can be combined with allother SQL for Oracle NoSQL Database clauses. For example:

sql-> SELECT a.customer_id, count(item_no) AS items_orderedFROM NESTED TABLES (customers.invoices a DESCENDANTS (customers.invoices.items))WHERE price > 10GROUP BY a.customer_id; +-------------+---------------+ | customer_id | items_ordered | +-------------+---------------+ | 1 | 3 | | 2 | 1 | +-------------+---------------+

2 rows returned

The following restrictions apply when using other clauses with NESTED TABLESclause:

Chapter 9Joins

9-18

Page 126: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

• ORDER BY and GROUP BY can be done only on the indexed fields of the targettable.

• If the NESTED TABLES clause contains a DESCENDANTS clause, the primary-key columns of the target table cannot be sorted in descending order.

Chapter 9Joins

9-19

Page 127: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

10Expressions

In general, an expression represents a set of operations to be executed in order toproduce a result. Expressions are built by combining other subexpressions usingoperators (arithmetic, logical, value and sequence comparisons), function calls, orother grammatical constructs. The simplest kinds of expressions are constants andreferences to variables or identifiers.

In SQL for Oracle NoSQL Database, the result of any expression is always asequence of zero or more items. Notice that a single item is considered equivalent to asequence containing that single item.

Note:

The examples shown in this chapter rely on the sample data shown in Example Data.

Path ExpressionsTo navigate inside complex values and select their nested values, SQL for OracleNoSQL Database supports path expressions. A path expression has an inputexpression followed by one or more steps.

<primary_expressions>.<step>*

Note:

A path expression over a table row must always start with the table's nameor the table's alias (if one was included in the FROM clause).

There are three kinds of path expression steps: field, filter, and slice steps. Field stepsare used to select field/entry values from records or maps. Filter steps are used toselect array or map entries that satisfy some condition. Slice steps are used to selectarray entries based on their position inside the containing array. A path expression canmix different kinds of steps.

All steps iterate over their input sequence, producing zero or more items for each inputitem. If the input sequence is empty, the result of the step is also empty. Otherwise,the overall result of the step is the concatenation of the results produced for each inputitem. The input item that a step is currently operating on is called the context item, andit is available within the step expression using the dollar sign ($) variable. This context-item variable exists in the scope created by the step expression.

10-1

Page 128: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

For all steps, if the context item is NULL, it is just added into the output sequence withno further processing.

In general, path expressions may return more than one item as their result. Such multi-item results can be used as input in two other kinds of expressions: sequence-comparison operators and array constructors.

Path expressions (if indexed) can also be used with the GROUP BY clause to return anatomic value for each grouping expression.

Field Step ExpressionsA field step selects the value of a field from a record or map. The field to select isspecified by its field name, which is either given explicitly as an identifier, or iscomputed by a name expression. The name expression must be of type string.

<primary_expression>.<id> | <string> | <var_ref> | <parenthesized_expr> | <func_call>*

As a simple example, the field step expression u.address.city:

SELECT id, u.address.city FROM Users u;

Retrieves the field "city" from the "address" column in the Users ("u") table.

A field step processes each context item as follows:

1. If the context item is an atomic item, it is skipped (the result is empty).

2. The name expression is evaluated. If the name expression returns the emptysequence or NULL, the context item is skipped. Otherwise, the evaluated nameexpression is passed to the next step.

3. If the context item:

• Is a record

and if that record contains a field identical to the evaluated name expression,then that field is returned. Otherwise, an error is raised.

• Is a map

and if that map contains a field identical to the evaluated name expression,then that field is returned. Otherwise, an empty result is returned.

If the context item ($) is an array, then the field step is applied to each element of thearray with the context item being set to the current array element. If the context item isan atomic item, it is skipped (the result is empty).

A field step expression (or any path expression) can also be used with the GROUP BYclause. For example, to find the number of users in each city:

SELECT city, count(*) FROM Users u GROUP BY u.address.city;

Chapter 10Path Expressions

10-2

Page 129: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Map Filter Step ExpressionsA map filter step is used with records and maps to select either the field name (keys)or the field values of the fields that satisfy a given condition. This condition is specifiedas a predicate expression inside parentheses. If the predicate expression is missing, itis assumed to be true — all the field names or values are returned.

<primary_expression>.keys | values (<predicate>)

where keys references the record's or map's field name, and values references therecord's or map's field values.

In addition to the context-item variable ($), the predicate expression may reference thefollowing two variables: $key is bound to the name of the context field — that is, thecurrent field in $, and $value is bound to the value of the context field. The predicateexpression must be boolean.

A simple example is u.expenses.keys($value > 1000), which selects all theexpenses greater than $1000. Combined with this query:

SELECT id, u.expenses.keys($value > 1000) FROM Users u;

all the user IDs and expense fields are returned where more than 1000 was spent.

A map filter step processes each context item as follows:

1. If the context item is an atomic item, it is skipped (the result is empty).

2. If the context item is a record or map, the step iterates over its fields. For eachfield, the predicate expression is evaluated. A NULL or an empty result from thepredicate expression is treated as a false value. If the predicate result is true, thecontext field is selected and either its name or its value is returned; otherwise thecontext field is skipped.

Note:

If the context item ($) is an array, then the map filter step is applied to eachelement of the array with the context item being set to the current arrayelement.

Array Filter Step ExpressionsAn array filter step is used with arrays to select elements of arrays by evaluating apredicate expression for each element. Elements are selected or rejected dependingon the results of the predicate expression. If the predicate expression is missing, it isassumed to be true — all the array elements are returned.

[<primary_expression>[<predicate_expression>]]

Chapter 10Path Expressions

10-3

Page 130: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Notice in the syntax that the entire expression is enclosed in square brackets ([]). Thisis the array constructor. Use of the array constructor is frequently required in order toobtain the desired result, and so we show it here. The use of the explicit arrayconstructor guarantees that the records in the result set will always have an array astheir second field. For example:

SELECT lastName,[ u.address.phones[$element.area = 650].number ] AS phoneNumbersFROM Users u;

Assume that u.address.phones references one or more phone numbers. Without thearray constructor, the result records would contain an array for users with more thanone phone (because the information would be held in an array in the store anyway),but just a single integer for users with just one phone. For users with just one phone,the phones field might not be an array (containing a single phone object), but just asingle phone object. If such a single phone object has area code 650, its number willbe selected, as expected.

In addition to the context-item variable ($), the predicate expression may reference thefollowing two variables: $element is bound to the current element in $, and $pos isbound to the position of the context element within $. Positions are counted startingwith 0.

An array filter step processes each context item as follows:

1. If the context item is not an array, an array is created and the context item isadded to that array. Then the array filter is applied to this single-item array.

2. If the context item is an array, the step iterates over the array elements andcomputes the predicate expression on each element.

The predicate expression must return a boolean item, or a numeric item, or theempty sequence, or NULL. A NULL or an empty result from the predicateexpression is treated as a false value. If the predicate result is true/false, thecontext element is selected/skipped, respectively. If the predicate result is anumber, the context element is selected only if $pos equals that number. Thismeans that if the predicate result is a negative number, or greater or equal to thearray size, the context element is skipped.

Array Slice Step ExpressionsAn array slice step is used with arrays to select elements of arrays based on elementposition. The elements to select are identified by specifying boundary positions whichidentify "low" position and "high" positions. Each boundary expression must return atmost one item of type LONG or INTEGER, or NULL. The low and/or the highexpression may be missing. The context-item variable ($) is available during thecomputation of the boundary expressions.

<primary_expression>[<low>:<high>]

For example, assume an array of connects ordered from the strongest connect(position 0) to the weakest, select the strongest connection for the user with id 10:

select connections[0] as strongestConnection from Userswhere id = 10;

Chapter 10Path Expressions

10-4

Page 131: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Select user 10's five strongest connections, and return the array (notice the use of thearray constructor):

select [ connections[0:4] ] as strongConnections from Userswhere id = 10;

Select user 10's five weakest connections:

select [ connections[size($) - 5 : ] ] as weakConnections from Userswhere id = 10;

An array slice step processes each context item as follows:

1. If the context item is not an array, an array is created and the context item isadded to that array. Then the array filter is applied to this single-item array.

2. If the context item is an array, the boundary expressions (if any) are evaluated.

If any boundary expression returns NULL or an empty result, the context item isskipped.

Otherwise, if the low expression is absent, or if it evaluates to less than 0, thelower boundary is set to 0. If the high expression is absent, or if it evaluates tohigher than the array_size -1, it is set to array_size - 1.

3. After the low and high positions are determined, the step selects all the elementspositions, inclusively, between those two boundaries. If the low position is greaterthan the high position, then no elements are selected.

Constant ExpressionsThere are five kinds of constants available:

• Strings.

Sequences of unicode characters enclosed in double or single quotes. Stringliterals are translated into String items.

• Integer numbers

Sequences of one or more digits. Integer literals are translated into Integer items,if their value fits in 4 bytes, otherwise into Long items.

• Real numbers

Representation of real numbers using “dot notation” and/or exponent. Real literalsare translated into Double items.

• The boolean values true and false.

• The JSON null value.

Column Reference ExpressionA column-reference expression returns the item stored in the specified column withinthe context row (the row that a WHERE, ORDER BY, or SELECT clause is currentlyworking on).

Chapter 10Constant Expressions

10-5

Page 132: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

A column-reference expression consists of one identifier, or two identifiers separatedby a dot. If there are two ids, the first is considered to be a table name or /alias, andthe second a column in that table. A single id refers to a column in the table referencedinside the FROM clause.

Notice that child tables in Oracle NoSQL Database have composite names using dotas a separator among multiple ids. As a result, a child-table name cannot be used in acolumn-reference expression; instead, a table alias must be used to access a childtable column using the two-id format. For example, if "Address" is a child table ofPersons, then:

SELECT id, p.Address.state FROM Persons p;

Variable Reference ExpressionA variable reference expression is: $<variablename>.

A variable-reference expression returns the item that the specified variable is currentlybound to. Syntactically, a variable-reference expression is just the name of thevariable.

Examples of variable usage can be found scattered throughout Working with complexdata. For example, Working With Maps discusses and shows the usage of severalimplicitly declared variables related to maps ($key and $value).

Searched Case ExpressionsCASE WHEN <expr> THEN <expr> (WHEN <expr> THEN <expr>)* (ELSE <expr>)? END;

The searched case expression consists of a number of when-then pairs, followed byan optional else clause at the end. Each when expression is a condition that mustreturn boolean. The then expressions as well as the else expression may return anysequence of items.

The case expression is evaluated by:

1. Evaluating the when expressions from top to bottom until the first one is discoveredthat returns true.

2. The then expression for the previously identified when is evaluated. This result isreturned as the result for the entire case expression.

3. If no when expression returns true, but there is an else expression, then thatexpression is evaluated and its result is the result of the entire case expression.

4. Otherwise, the result of the entire case expression is the empty sequence.

Chapter 10Variable Reference Expression

10-6

Page 133: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

For example, construct a map using the map constructor ({}) in which the phones:element is either the contents of the phones column, or a string to indicate nothing wasfound in that column:

select { “last_name” : u.lastName, “phones” : case when exists u.address.phones then u.address.phones else “Phone info absent at the expected place” end, “high_expenses” : [ u.expenses.keys($value > 5000) ] }from Users u;

For more examples of using searched case expressions, see Using Searched Case.

Cast ExpressionsThe cast expression creates, if possible, new items of a given target type from theitems of its input sequence.

CAST (<input_sequence> AS <target_type><quantifier>)

Cast expressions are evaluated as follows:

1. A cardinality check is performed based on the <quantifier>. If <quantifier> is:

• *

then <input_sequence> may have any number of items.

• +

then <input_sequence> must have at least one item.

• ?

then <input_sequence> must have at most one item.

• No quantifier

then <input_sequence> must exactly one item.

If this check fails, an error is raised.

2. Each input item is cast to the <target_type> according to the following recursiverules:

• If the type of the input item is equal to the target item type, the cast is a noop:the input item itself is returned.

• If the target type is a wildcard type, the cast is a noop if the type of the inputitem is a subtype of the wildcard type; otherwise an error is raised.

• If the target type is JSON, then:

– an error is raised if the input item has a non-json atomic type.

– if the input item has a type that is a json atomic type or ARRAY(JSON) orMAP(JSON), the cast is a noop.

Chapter 10Cast Expressions

10-7

Page 134: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

– if the input item is a non-json array, a new array of type ARRAY(JSON) isconstructed, each element of the input array is cast to JSON, and theresulting item is appended into the new json array.

– if the input item is a non-json map, a new map of type MAP(JSON) isconstructed, each field value of the input map is cast to JSON, and theresulting value together with the associated field name are inserted intothe new json map.

– if the input item is a record, it is cast to a map of type MAP(JSON).

• If the target type is an array type, an error is raised if the input item is not anarray. Otherwise, a new array is created whose type is the target type. Eachelement in the input array is cast to the element type of the target array, andeach such item is appended into the new array.

• If the target type is a map type, an error is raised if the input item is not a mapor a record. Otherwise, a new map is created whose type is the target type.Each element in the input map/record is cast to the element type of the targetmap, and the resulting value together with the associated field name isinserted into the new map.

• If the target type is a record type, an error is raised if the input item is not arecord or a map. Otherwise, a new record is created whose type is the newtarget type.

If the input item is a record, its type must have the same fields and in the sameorder as the target type. In this case, each field value in the input record iscast to the value type of the corresponding field in the target type, and theresulting field value together with the associated field name is added to thenew record.

If the input item is a map, then for each map field, if the field name exists in thetarget type, the associated field value is cast to the value type of thecorresponding field in the target type, and the resulting field value togetherwith the associated field name is added to the new record. Any fields in thenew record whose names do not appear in the input map have theirassociated field values set to their default values.

• If the target type is a string, the input item may be of any type. In other words,every data type can be cast to a string. For complex items their “string value”is a json-text representation of their value. For timestamps, their string value isin UTC and has the format uuuu-MM-dd['T'HH:mm:ss]. For binary items, theirstring value is a base64 encoding of their bytes.

• If the target type is an atomic type other than string, the input item must alsobe atomic. Among atomic items and types the following casts are allowed:

– Every numeric item can be cast to every other numeric type. The cast isdone as in Java.

– String items may be cast-able to all other atomic types. Whether the castsucceeds depends on whether the actual string value can be parsed into avalue that belongs to the domain of the target type.

– Timestamp items are cast-able to all the timestamp types. If the targettype has a smaller precision that the input item, the resulting timestamp isthe one closest to the input timestamp in the target precision. Forexample, consider the following 2 timestamps with precision 3: 2016-11-01T10:00:00.236 and 2016-11-01T10:00:00.267. The result of casting

Chapter 10Cast Expressions

10-8

Page 135: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

these timestamps to precision 1 is: 2016-11-01T10:00:00.2 and2016-11-01T10:00:00.3, respectively.

For examples of using the cast expression, see Casting Datatypes.

Sequence Transform ExpressionA sequence transform expression transforms a sequence to another sequence.Syntactically it looks like a function. The first argument is an expression that generatesthe sequence to be transformed (the input sequence) and the second argument is a“mapper” expression that is computed for each item of the input sequence.

The result of the seq_transform expression is the concatenation of sequencesproduced by each evaluation of the mapper expression. The mapper expression canaccess the current input item using the $ variable.

For example, assume a sales table with the following rows (shown here in JSONformat):

{"id":1, "sales": { "acctno" : 349, "year" : 2000, "month" : 10, "day" : 23, "state" : "CA", "city" : "San Jose", "storeid" : 76, "prodcat" : "veggies", "items" : [{ "prod" : "tomatoes", "qty" : 3, "price" : 10.0 }, { "prod" : "carrots", "qty" : 1, "price" : 5.0 }, { "prod" : "peppers", "qty" : 1, "price" : 15.0 } ] }}

Assume that the following index exists on the sales table:

CREATE INDEX on sales(sale.acctno as integer, sale.year as integer, sale.prodcat as string);

Then, we can write the following query using the seq_transform function, whichreturns the total sales per account number and year:

SELECT t.sale.acctno,t.sale.year,SUM(seq_transform(t.sale.items[], $.price * $.qty)) as sales FROM sales t GROUP BY t.sale.acctno, t.sale.year;

Chapter 10Sequence Transform Expression

10-9

Page 136: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

11Operators

This chapter describes the various operators you can use with your SQL expressions.

Note:

The examples shown in this chapter rely on the sample data shown in Example Data.

Logical OperatorsThe binary AND and OR operators and the unary NOT operator have the usualsemantics. Their operands are conditional expressions, which must have typeBOOLEAN.

An empty result from an operand is treated as the false value. If an operand returnsNULL then:

• The AND operator returns false if the other operand returns false; otherwise, itreturns NULL.

• The OR operator returns false if the other operand returns false; otherwise, itreturns NULL.

• The NOT operator returns NULL.

Value Comparison OperatorsValue comparison operators are primarily used to compare 2 values, one produced bythe left operand and another from the right operand. The available value comparisonoperators are:

• =

• !=

• >

• >=

• <

• <=

If any operand returns more than one item, an error is raised. If both operands returnthe empty sequence, the operands are considered equal (so true will be returned if theoperator is =, <=, or >=). If only one of the operands returns empty, the result of thecomparison is false unless the operator is !=.

11-1

Page 137: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Among atomic items, if the types of the items are not comparable, false is returned.The following rules defined what atomic types are comparable and how thecomparison is done in each case.

• A numeric item is comparable with any other numeric item. If an integer/long valueis compared to a float/double value, the integer/long will first be cast to float/double.

• A string item is comparable to another string item.

A string item is also comparable to an enum item. In this case, before thecomparison the string is cast to an enum item in the type of the other enum item.Such a cast is possible only if the enum type contains a token whose string valueis equal to the source string. If the cast is successful, the two enum items are thencompared as explained in the next bullet; otherwise, the two items areincomparable and false is returned.

• Two enum items are comparable only if they belong to the same type. If so, thecomparison is done on the ordinal numbers of the two enums (not their stringvalues).

• Binary and fixed binary items are comparable with each other for equality only.The 2 values are equal if their byte sequences have the same length and areequal byte-per-byte.

• A boolean item is comparable with another boolean item.

• A timestamp item is comparable to another timestamp item, even if their precisionsare different.

• JNULL (JSON null) is comparable with JNULL. If the comparison operator is !=,JNULL is also comparable with every other kind of item, and the result of such acomparison is always true, except when the other item is also JNULL.

The semantics of comparisons among complex items is:

• A record is comparable with another record for equality only, and only if theycontain comparable values. To be equal, the 2 records must have equal sizes(number of fields) and for each field in the first record, there must exist a field inthe other record such that the two fields are at the same position within theircontaining records, have equal field names, and equal values.

• A map is comparable with another map for equality only, and only if they containcomparable values. To be equal, the 2 maps must have equal sizes (number offields) and for each field in the first map, there must exist a field in the other mapsuch that the two fields have equal names and equal values.

• An array is comparable to another array, if the elements of the 2 arrays arecomparable pair-wise. Comparison between 2 arrays is done lexicographically.That is, the arrays are compared like strings, with the array elements playing therole of the "characters" to compare.

As with atomic items, if two complex items are not comparable according to the aboverules, false is returned. Comparisons between atomic and complex items return falsealways.

Chapter 11Value Comparison Operators

11-2

Page 138: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Note:

The reason for returning false for incomparable items, instead of raising anerror, is to handle schema-less applications where different table rows maycontain very different data, or differently shaped data. As a result, even thewriter of the query may not know what kind of items an operand may returnand an operand may indeed return different kinds of items from differentrows. Nevertheless, when the query writer compares “something” with, say,an integer, they expect that the “something” will be an integer and they wouldlike to see results from the table rows that fulfill that expectation, instead ofthe whole query being rejected because some rows do not fulfill theexpectation.

Sequence Comparison OperatorsComparisons between two sequences is done using the following operators:

• =any

• !=any

• >any

• >=any;

• <any

• <=any

The result of an any operator on two input sequences S1 and S2 is true only if:

1. There is a pair of items, i1 and i2; and

2. i1 belongs to S1, and i2 belongs to S2; and

3. i1 and i2 compare true using the corresponding value-comparison operator.

Otherwise, if any of the input sequences contains NULL, the result is NULL.

Otherwise, the result is false.

IS NULL OperatorThe IS NULL operator test whether the result of its input expression is SQL NULL.(SQL NULL is used when a non-JSON field is set to NULL.) IS NULL requires an inputexpression that returns a single item. If that single item is SQL NULL, then IS NULLreturns true.

A table field can be NULL if it is explicitly set to NULL, or if the table field is simply notpopulated when you import data.

If the input expression returns more than one item, an error is raised. If the result ofthe input expression is empty, IS NULL returns false. This means that IS NULL cannotbe used to identify missing fields from JSON columns. Use the Exists Operatorinstead.

Chapter 11Sequence Comparison Operators

11-3

Page 139: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Note:

IS NULL returns false for JSON fields which exist but are set to NULL. This isbecause for JSON data, NULL is the JSON NULL, not the SQL NULL.

IS NOT NULL can also be used. It is equivalent to:

NOT (IS NULL <expression>)

For an example of using IS NULL and IS NOT NULL, see Filtering Results.

Exists OperatorThe exists operator checks whether a sequence is empty. True is returned if thesequence is not empty.

Note that this operator returns true even if the sequence contains null data. So forstrongly typed data (that is, non-JSON data columns), this operator will always returntrue because on data import the column will be always at minimum populated with theSQL NULL. To check whether strongly typed data is NULL, use the IS NULL Operator.

For an examples of using the exists operator, see Using WHERE EXISTS with JSON.

Is-Of-Type OperatorReturns true if the input sequence matches the identified type.

<sequence> IS OF TYPE (<type>*|+|?,<type>*|+|?,...])

or

<sequence> IS NOT OF TYPE (<type>*|+|?,<type>*|+|?,...)

The is-of-type operator checks the input sequence type against one or more targetsequence types. It returns true if both of the following conditions are true:

• The cardinality of the input sequence matches the quantifier of the target type:

– If the quantifier is *, the input sequence may have any number of items.

– If the quantifier is +, the input sequence must have at least one item.

– If the quantifier is ?, the input sequence must have at most one item.

– If there is no quantifier, the input sequence must have exactly one item.

• All of the items in the input sequence are instance of the specified type(s). For thepurpose of this check, a NULL is not considered to be and instance of any type.

SQL for Oracle NoSQL Database's subtype-supertype relationship model isrelevant to the usage of this operator. See Type Hierarchy for more information.

Chapter 11Exists Operator

11-4

Page 140: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

If the cardinality requirement is met and the input sequence contains a NULL, thisoperator returns NULL. In all other cases, the result is false.

Note:

If the number of the target types is greater than one, the expression isequivalent to OR-ing that number of is-of-type expressions, each having onetarget type.

For an example of using is-of-type, see Examining Data Types JSON Columns.

Chapter 11Is-Of-Type Operator

11-5

Page 141: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

12Constructors

SQL for Oracle NoSQL Database offers two constructors that you can use: Array andMap constructors.

Note:

The examples shown in this chapter rely on the sample data shown in Example Data.

Array Constructors[ <expression>, <expression>, ... ]

An array constructor constructs a new array out of the items returned by theexpressions inside the square brackets. These expressions are computed left to rightand the produced items are appended to the array. Any NULLs produced by the inputexpressions are skipped (arrays cannot contain NULLs).

The type of the constructed array is determined during query compilation, based onthe types of the input expressions and the usage of the constructor expression.Specifically, if a constructed array can be inserted in another constructed array andthis “parent” array has type ARRAY(JSON), then the “child” array will also have typeARRAY(JSON). This is because "typed" data is not allowed inside JSON data.

For example, the use of the explicit array constructor here means that the field willexist in all returned rows, even if the path inside the array constructor returns empty.Without this constructor, a NULL can be returned for the field. With it, an empty resultreturns an empty array.

select firstname, lastname, [u.expenses.keys($value > 1000)] AS Expensesfrom Users u;

Map Constructors{ <expression>:<expression>, <expression:<expression>, ... }

A map constructor constructs a new map out of the items returned by the expressionsinside the curly brackets. These expressions come in pairs: each pair computes onefield.

12-1

Page 142: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

The first expression in a pair must return at most one string, which serves as the field'sname. If the field name expression returns the empty sequence, no field isconstructed.

The second expression returns the field value. If this expression returns more than oneitem, an array is implicitly constructed to store the items, and that array becomes thefield value. If the field value expression returns the empty sequence, no field isconstructed.

If the computed name or value for a field is NULL the field is skipped (maps cannotcontain NULLs).

The type of the constructed map is determined during query compilation, based on thetypes of the input expressions and the usage of the constructor expression.Specifically, if a constructed map can be inserted in another constructed map and this“parent” map has type MAP(JSON), then the “child” map will also have typeMAP(JSON). This is because "typed" data is not allowed inside JSON data.

For example, construct a map consisting of user's last name and their phone numbers:

select { “last_name” : u.lastName, “phones” : u.address.phones}from Users u;

Chapter 12Map Constructors

12-2

Page 143: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

13Built-in Functions

You can use function-call expressions to invoke functions, which currently can only bebuilt-in (system) functions. The available built-in system functions are as follows:

• Size function.

Returns the size (number of fields/entries) of a complex item such as a record,array, or map. For an example of usage, see Using the size() Function

• Timestamp functions.

Returns specific information from a Timestamp data type, such as the year ormonth that the data represents. See Timestamp Functions for a description ofthose functions. See Working with Timestamps for an example of how to use theTimestamp functions.

• Sequence concatenation function.

Used to concatenate one sequence to another. See Sequence ConcatenationFunction for a description of this function. See Adding Elements to an Array for anexample of how to use this function.

• Time to Live functions.

Extracts Time to Live properties for table rows. See Time to Live Functions for alist of these functions.

• Time functions.

Miscellaneous functions related to the system clock. See Time Functions for a listof these functions.

Time to Live FunctionsA time to live (TTL) value can be set on a table by table, or row by row basis. Data thatreaches its time to live value is said to have expired, and it will no longer be returnedas the result of a query. For information on setting TTL values on a row by row basis,see Managing Time to Live Values.

TTL properties are not a normal part of table schema. They are not stored as top-levelcolumns or nested fields, and as such cannot be queried using ordinary querymechanisms. Instead, you can use the following functions to examine a row's TTLvalues:

• <integer> remaining_hours(<row>)

Returns the number of full hours remaining until the row expires. A negativenumber is returned if the row has no expiration time.

• <integer> remaining_days(<row>)

Returns the number of full days remaining until the row expires. A negativenumber is returned if the row has no expiration time.

• <timestamp(0)> expiration_time(<row>)

13-1

Page 144: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Returns the expiration time of the row as a timestamp value of precision zero. Ifthe row has no expiration time, this function returns 1970-01-01T00:00:00.000.

• <long> expiration_time_millis(<row>)

Returns the expiration time of the row as the number of milliseconds since January1, 1970 UTC. Zero (0) is returned if the row has no expiration time.

All of these functions require a row as input. The only expression that returns a row isa row variable; that is, a table alias whose name starts with $.

For an example of using these functions, see Managing Time to Live Values.

Time FunctionsThe following functions can be used to return time information from the system clock:

• <long> current_time_millis()

Returns the current time in UTC as the number of milliseconds since January 1,1970 UTC.

• <timestamp(3)> current_time()

Returns the current time in UTC as a timestamp value with millisecond precision.

For an example of using current_time(), see Updating Existing Map Elements, and Managing Time to Live Values.

Chapter 13Time Functions

13-2

Page 145: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

14SQL Statements

As with standard SQL, you can use SQL for Oracle NoSQL Databaseto insert orupdate a table row. However, SQL for Oracle NoSQL Database includes extensions tohandle the richer data model that Oracle NoSQL Database offers.

When you execute an INSERT statement using SQL for Oracle NoSQL Database, thedatabase inserts a new record to a table.

When you execute an UPDATE statement using SQL for Oracle NoSQL Database, theupdate takes place directly, resulting in a very efficient way to update data. UsingUPDATE, you do not need to retrieve data from the store, modify it, and then write thedata back to the store. Instead, you send the UPDATE statement to the store, whichdirectly updates the row without any further network traffic.

For examples of using the INSERT statement, see Adding Table Rows using INSERTand UPSERT.

For examples of using the UPDATE statement, see Modifying Table Rows usingUPDATE Statements.

Insert Statement SyntaxThe insert statement is used to construct a new row and insert it in a specified table. Ifthe INSERT keyword is used, the row will be inserted only if it does not exist already. Ifthe UPSERT keyword is used, the row will be inserted if it does not exist already,otherwise the new row will replace the existing one.

The insert statement syntax is:

[<prolog>](INSERT | UPSERT) INTO <table_name> [[AS] <table_alias>][(<column_name> [, <column_name>]*)]VALUES (<insert_clause> [, <insert_clause>]*)[SET TTL <insert_ttl_clause>][<returning_clause>];

returning_clause: RETURNING select_list ;

insert_clause: DEFAULT | expr;

ttl_clause: (expr (HOURS | DAYS)) | (USING TABLE DEFAULT);

Where:

• The <prolog>, if present, is used to declare external variables. Like querystatements, insert statements may start with declaration of external variables usedin the rest of the statement. However, contrary to inserts, external variables can beused in queries without being declared. This is because inserts do not query any

14-1

Page 146: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

data, and as result, knowing the type of external variables in advance is notimportant as there isn’t any query optimization to be done.

• After the table name, an optional columns list may be specified. This list containsthe column names for a subset of the table’s columns. The subset must include allthe primary key columns. If no columns list is present, the default columns list isthe one containing all the columns of the table, in the order they are specified inthe CREATE TABLE statement.

• The columns in the column list correspond one-to-one to the expressions (orDEFAULT keywords) listed after the VALUES clause (an error is raised if the numberof expressions/ DEFAULTs is not the same as the number of columns). Theseexpressions/ DEFAULTs compute the value for their associated column in the newrow. Specifically, each expression is evaluated and it’s returned value is cast tothe type of its associated column.

An error is raised if an expression returns more than one item. If an expressionreturns no result, NULL is used as the result of that expression. If instead of anexpression, the DEFAULT keyword appears in the VALUES list, the default value ofthe associated column is used as the value of that column in the new row. Thedefault value is also used for any missing columns, when the number of columnsin the columns list is less than the total number of columns in the table.

The expressions in the VALUES list may reference external variables, whichcontrary to query statements, do not need to be declared in a declarations section.

• Following the VALUES list, a SET TTL clause may be used to set the expiration timeof the new row. In case of UPSERT, the SET TTL clause may be used to update theexpiration time of an existing row.

Every row has an expiration time, which may be infinite, and which is computed interms of a Time-To-Live (TTL) value that is specified as a number of days orhours. Specifically, for a TTL value of N hours/days, where N is greater than zero,the expiration time is computed as the current time (in UTC) plus N hours/days,rounded up to the next full hour/day. For example, if the current time is2017-06-01T10:05:30.0 and N is 3 hours, the expiration time will be2017-06-01T14:00:00.0. If N is 0, the expiration time is infinite.

As shown in the syntax, the SET TTL clause comes in two flavors. When the USINGTABLE DEFAULT syntax is used, the TTL value is set to the table default TTL thatwas specified in the CREATE TABLE statement. Otherwise, the SET TTL clausecontains an expression, which computes a new TTL value. If the result of thisexpression is empty, the default TTL of the table is used. Otherwise, theexpression must return a single numeric item, which is cast to an integer N. If N isnegative, it is set to 0.

To the right of the TTL expression, the keyword HOURS or DAYS must be used tospecify whether N is a number of hours or days, respectively. If the insertstatement contains a SET TTL clause, an expiration time is computed as describedabove and becomes the expiration time of the inserted or updated row.

If no SET TTL clause is used, the default table TTL is used to compute theexpiration time of an inserted row, but for an updated row its expiration time is notupdated.

• The last part of the insert statement is the RETURNING clause. If not present, theresult of the update statement is a record with a single field whose name is“NumRowsInserted” and whose value is the number of rows inserted: 0 if the rowexists already, or 1 otherwise. Otherwise, if there is a RETURNING clause, it acts the

Chapter 14Insert Statement Syntax

14-2

Page 147: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

same way as the SELECT clause. It can be a "*", in which case, a full row will bereturned, or it can have a list of expressions specifying what needs to be returned.

In the case of an INSERT statement where no insertion is actually done (becausethe row exists already), the RETURNING clause acts on the existing row. Otherwise,the RETURNING clause acts on the new row.

Update Statement SyntaxThe update statement syntax is:

[<prolog>]UPDATE <table_name> [AS <table_alias>] <update_clause>[, <update_clause>]*WHERE <expr>[<returning_clause>];

where:

• <prolog> is optional, and can be used to declare external variables.

• <table_name> is the name of the table you are updating.

• <table_alias> is optional, but it can be omitted only if top-level columns are beingaccessed by the statement. Otherwise, as is the case for read-only queries, analias is required as the first step in path expressions that access nested fields.

• <update_clause> describe one or more update actions to take on the table. Theseare described in detail in the remainder of this chapter.

• The WHERE clause specifies which row to update. Only single row updates areallowed, so the WHERE clause must specify an exact primary key.

• <returning_clause> is optional, and it indicates what should be returned as a resultof the update. If it is not specified, the number of rows updated is returned. If norows match the WHERE clause, then 0 is returned. If a match is found, then 1 isalways returned because update statements can only update a single row at atime.

The <returning_clause> can also act as a SELECT clause. If * is specified, thenthe entire updated row is returned. Otherwise, the <returning_clause> can providea list of expressions that indicate what should be returned from the updated table.

The rest of this chapter describes the <update_clause> in detail.

Update ClausesUpdate clauses are used to describe what modifications are to be made to a table row.There are five types of clauses that you can use:

• SET

Updates the value of one or more fields. See SET Clause for details.

• ADD

Adds new elements to one or more arrays. See ADD Clause for details.

• PUT

Chapter 14Update Statement Syntax

14-3

Page 148: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Adds new fields to one or more maps, or updates the value of an existing mapfield. See PUT Clause for details.

• REMOVE

Removes elements/fields from one or more arrays/maps. See REMOVE Clausefor details.

• SET TTL

Used to modify the row's expiration time. See SET TTL Clause for details.

Multiple clauses and a combination of clauses can be used by seperating it by comma.For example:

update_clause :(SET set_clause (COMMA (update_clause | set_clause))*) |(ADD add_clause (COMMA (update_clause | add_clause))*) |(PUT put_clause (COMMA (update_clause | put_clause))*) |(REMOVE remove_clause (COMMA remove_clause)*) ;

SET Clause

set <target_expr> = <new-value_expr>

The SET clause changes the value of existing information in the targeted table. Itstarget expression which identifies the information to change. Its new-value expressionidentifies what the targeted information will become.

• Target Expression

A target expression can be atomic or complex, but it will always be nested inside acomplex item (its parent item). For each such target expression, the new-valueexpression is evaluated and the new-value results are used to replace the targetitem.

If the target expression returns a NULL item, then either the target item itself is theNULL item or one of its ancestors is NULL. If the target item is NULL, the result ofthe new-value expression are used to replace the NULL. If one of the target item'sancestors are NULL, then the entire clause is a noop.

• New-Value Expression

The new-value expression can return zero or more items. If it returns an emptyresult, the SET is a noop. If it returns more than one item, the items are enclosedinside a newly constructed array in the same was as the way the SELECT clausetreats multi-valued expressions in the select list. The result of the new-valueexpression is then cast to the type expected by the parent item for the target field.(See Cast Expressions for details.) If the cast fails, an error is raised; otherwisethe new item replaces the target item within the parent item.

The new-value expression may reference the implicitly declared variable $, whichis bound to the current target item. Use of the $ variable makes it possible to havetarget expressions that return more than one item. In this case the SET clause williterate over the set of target items, bind the $ variable for each target item,compute the new-value expression, and replace the target item with the result ofthe new-value expression.

Chapter 14Update Statement Syntax

14-4

Page 149: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

For examples of using a SET clause, see Changing Field Values, Changing anExisting Element in an Array, and Updating Existing Map Elements

ADD Clause

add <target_expr> <position_expression> <new-elements_expr>

or

add <target_expr> <new-elements_expr>

The ADD clause is used to add new elements into one or more arrays. It consists of:

• a target expression, which should return one or more array items,

• an optional position expression, which specifies the position within the array wherethe new element(s) should be placed at,

• and a new-elements expression that returns the new elements to insert.

This clause iterates over the sequence returned by the target expression. For eachtarget item, if the item is not an array it is skipped. Otherwise, the position expression(if present) and the new-elements expression are computed for the current targetarray. These two expressions may reference the $ variable, which is bound to thecurrent target array.

If the position expression is missing, or if it returns an empty result, the new elementsare appended at the end of the target array. An error is raised if the positionexpression returns more than one item or a non-numeric item. Otherwise, the returneditem is cast to an integer. If this integer is less than 0, it is set to 0. If it is greater orequal to the array size, the new elements are appended.

If the the new-values expression returns nothing, the ADD clause is a noop.Otherwise, each item returned by this expression is cast to element type of the array.An error is raised if any of these casts fails. Otherwise, the new elements are insertedinto the target array at the indicated position.

For examples of using an ADD clause, see Adding Elements to an Array.

PUT Clause

put <target_expression> <new-fields_expression>

The PUT clause is used to add new fields into one or more maps. It consists of:

• a target expression which should return one or more map items,

• and a new-fields expression that returns one or more maps or records. These arethe fields that are inserted in the target maps.

The PUT clause iterates over the sequence returned by the target expression. Foreach target item, if the item is not a map it is skipped. Otherwise, the new-fieldsexpression is computed for the current target map. The new-maps expression mayreference the $ variable, which is bound to the current target map.

Chapter 14Update Statement Syntax

14-5

Page 150: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

If the the new-fields expression returns nothing, the PUT is a noop. Otherwise, foreach item returned by the new-fields expression, if the item is not a map or a record, itis skipped. If the item is a map or record, the fields of the map/record are “merged” intothe current target map. This merge operation will insert a new field into the target mapif the target map does not already have a field with the same key. Otherwise it will setthe value of the target field to the value of the new field.

For examples of using a PUT clause, see Adding Elements to a Map.

REMOVE Clause

remove <target_expression>

The remove clause consists of a single target expression, which computes the items tobe removed. The REMOVE clause iterates over the target items, and for each item:

• If its parent is a record, an error is raised.

• If the target item is not NULL, it is removed from its parent.

• If the target item is NULL, it is skipped.

Note that if the target item is NULL, then one of its ancestors must be NULL. Thisis because arrays and maps cannot contain NULLs. Consequently, the target itemis skipped because of the NULL ancestor.

For examples of using the REMOVE clause, see Removing Elements from Arrays and Removing Elements from a Map.

SET TTL Clause

set TTL <add_expression> HOURS|DAYS

or

set TTL USING TABLE DEFAULT

Every table row has an expiration time that is specified in terms of a Time to Live (TTL)value. TTL values are specified as a number of days or hours. If zero (0), the row willnever expire. If a row expires, its data can no longer appear in query results.

The expiration time for a row is always computed when the row is first inserted into atable. However, you can use the SET TTL clause to specify a new expiration time. Thevalue you specify for this clause is used to compute the new expiration time.

The SET TTL clause comes in two flavors. The first contains an expression whichcomputes a new TTL value as follows:

1. If the result of this expression is empty, the SET TTL clause is a noop.

2. If the expression result is not empty, it is cast to an integer.

3. If the resulting integer is negative, it is set to 0. This means the table row will neverexpire.

4. If the resulting integer is non-negative, it must be followed by a unit designation ofeither HOURS or DAYS.

Chapter 14Update Statement Syntax

14-6

Page 151: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

5. The new expiration time is computed based on the current time (in UTC) plus thenumber of hours/days computed in <add_expression> rounded up to the next fullhour/day. That is, if the current time is 2017-06-01T10:05:30.0 and the TTL valueevaluates to 3 hours, the expiration time will be 2017-06-01T14:00:00.0.

For an example of using the SET TTL clause, see Managing Time to Live Values.

Chapter 14Update Statement Syntax

14-7

Page 152: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

AIntroduction to the SQL for Oracle NoSQLDatabase Shell

This appendix describes how to configure, start and use the SQL for Oracle NoSQLDatabase shell to execute SQL statements. This section also describes the availableshell commands.

You can directly execute DDL, DML, user management, security, and informationalstatements using the SQL shell.

Running the SQL ShellYou can run the SQL shell interactively or use it to run single commands. Here is thegeneral usage to start the shell:

java -jar KVHOME/lib/sql.jar -helper-hosts <host:port[,host:port]*> -store <storeName> [-username <user>] [-security <security-file-path>] [-timeout <timeout ms>] [-consistency <NONE_REQUIRED(default) | ABSOLUTE | NONE_REQUIRED_NO_MASTER>] [-durability <COMMIT_SYNC(default) | COMMIT_NO_SYNC | COMMIT_WRITE_NO_SYNC>] [single command and arguments]

where:

• -consistency

Configures the read consistency used for this session.

• -durability

Configures the write durability used for this session.

• -helper-hosts

Specifies a comma-separated list of hosts and ports.

• -store

Specifies the name of the store.

• -timeout

Configures the request timeout used for this session.

• -username

Specifies the username to login as.

A-1

Page 153: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

For example, you can start the shell like this:

java -jar KVHOME/lib/sql.jar-helper-hosts node01:5000 -store kvstoresql->

This command assumes that a store kvstore is running at port 5000. After the SQLstarts succcessfully, you execute queries. In the next part of this document, you willfind an introduction to SQL for Oracle NoSQL Database and how to create querystatements.

If you want to import records from a file in either JSON or CSV format, you can use theimport command. For more information see import.

If you want to run a script, use the load command. For more information see load.

For a complete list of utility commands accessed through "java -jar" <kvhome>/lib/sql.jar <command> see Shell Utility Commands.

Configuring the shellYou can also set the shell start-up arguments by modifying the configurationfile .kvclirc found in your home directory.

Arguments can be configured in the .kvclirc file using the name=value format. Thisfile is shared by all shells, each having its named section. [sql] is used for the Queryshell, while [kvcli] is used for the Admin Command Line Interface (CLI).

For example, the .kvclirc file would then contain content like this:

[sql]helper-hosts=node01:5000store=kvstoretimeout=10000consistency=NONE_REQUIREDdurability=COMMIT_NO_SYNCusername=rootsecurity=/tmp/login_root

[kvcli]host=node01port=5000store=kvstoreadmin-host=node01admin-port=5001username=user1security=/tmp/login_useradmin-username=rootadmin-security=/tmp/login_roottimeout=10000consistency=NONE_REQUIREDdurability=COMMIT_NO_SYNC

Appendix AConfiguring the shell

A-2

Page 154: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Shell Utility CommandsThe following sections describe the utility commands accessed through "java -jar"<kvhome>/lib/sql.jar <command>".

The interactive prompt for the shell is:

sql->

The shell comprises a number of commands. All commands accept the following flags:

• -help

Displays online help for the command.

• ?

Synonymous with -help. Displays online help for the command.

The shell commands have the following general format:

1. All commands are structured like this:

sql-> command [arguments]

2. All arguments are specified using flags that start with "-"

3. Commands and subcommands are case-insensitive and match on partialstrings(prefixes) if possible. The arguments, however, are case-sensitive.

connect

connect -host <hostname> -port <port> -name <storeName>[-timeout <timeout ms>][-consistency <NONE_REQUIRED(default) | ABSOLUTE | NONE_REQUIRED_NO_MASTER>][-durability <COMMIT_SYNC(default) | COMMIT_NO_SYNC | COMMIT_WRITE_NO_SYNC>][-username <user>] [-security <security-file-path>]

Connects to a KVStore to perform data access functions. If the instance is secured,you may need to provide login credentials.

consistency

consistency [[NONE_REQUIRED | NONE_REQUIRED_NO_MASTER |ABSOLUTE] [-time -permissible-lag <time_ms> -timeout <time_ms>]]

Configures the read consistency used for this session.

Appendix AShell Utility Commands

A-3

Page 155: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

describe

describe | desc [as json] {table table_name [field_name[,...] ] | index index_name on table_name }

Describes information about a table or index, optionally in JSON format.

Specify a fully-qualified table_name as follows:

Entry specification Description

table_name Required. Specifies the full table name. Withoutfurther qualification, this entry indicates a tablecreated in the default namespace (sysdefault),which you do not have to specify.

parent-table.child-table Specifies a child table of a parent. Specify theparent table followed by a period (.) before the childname. For example, if the parent table is Users,specify the child table named MailingAddress asUsers.MailingAddress.

namespace-name:table-name Specifies a table created in the non-defaultnamespace. Use the namespace followed by acolon (:). For example, to reference table Users,created in the Sales namespace, enter table_nameas Sales:Users.

Following is the output of describe for table ns1:t1:

sql-> describe table ns1:t1; === Information === +-----------+------+-----+-------+----------+----------+--------+----------+---------+-------------+ | namespace | name | ttl | owner | sysTable | r2compat | parent | children | indexes | description | +-----------+------+-----+-------+----------+----------+--------+----------+---------+-------------+ | ns1 | t1 | | | N | N | | | | | +-----------+------+-----+-------+----------+----------+--------+----------+---------+-------------+

=== Fields === +----+------+---------+----------+-----------+----------+------------+----------+ | id | name | type | nullable | default | shardKey | primaryKey | identity | +----+------+---------+----------+-----------+----------+------------+----------+ | 1 | id | Integer | N | NullValue | Y | Y | |

Appendix AShell Utility Commands

A-4

Page 156: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

+----+------+---------+----------+-----------+----------+------------+----------+ | 2 | name | String | Y | NullValue | | | | +----+------+---------+----------+-----------+----------+------------+----------+

sql->

This example shows using describe as json for the same table:

sql-> describe as json table ns1:t1;{ "json_version" : 1, "type" : "table", "name" : "t1", "namespace" : "ns1", "shardKey" : [ "id" ], "primaryKey" : [ "id" ], "fields" : [ { "name" : "id", "type" : "INTEGER", "nullable" : false, "default" : null }, { "name" : "name", "type" : "STRING", "nullable" : true, "default" : null } ]}

durability

durability [[COMMIT_WRITE_NO_SYNC | COMMIT_SYNC |COMMIT_NO_SYNC] | [-master-sync <sync-policy> -replica-sync <sync-policy>-replica-ask <ack-policy>]] <sync-policy>: SYNC, NO_SYNC, WRITE_NO_SYNC<ack-policy>: ALL, NONE, SIMPLE_MAJORITY

Configures the write durability used for this session.

exit

exit | quit

Exits the interactive command shell.

Appendix AShell Utility Commands

A-5

Page 157: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

help

help [command]

Displays help message for all shell commands and sql command.

history

history [-last <n>] [-from <n>] [-to <n>]

Displays command history. By default all history is displayed. Optional flags are usedto choose ranges for display.

import

import -table table_name -file file_name [JSON | CSV]

Imports records from the specified file into table table_name.

Specify a fully-qualified table_name as follows:

Entry specification Description

table_name Required. Specifies the full table name. Withoutfurther qualification, this entry indicates a tablecreated in the default namespace (sysdefault),which you do not have to specify.

parent-table.child-table Specifies a child table of a parent. Specify theparent table followed by a period (.) before the childname. For example, if the parent table is Users,specify the child table named MailingAddress asUsers.MailingAddress.

namespace-name:table-name Specifies a table created in the non-defaultnamespace. Use the namespace followed by acolon (:). For example, to reference table Users,created in the Sales namespace, enter table_nameas Sales:Users.

Use -table to specify the name of a table into which the records are loaded. Thealternative way to specify the table is to add the table specification "Table:table_name" before its records in the file.

For example, this file contains the records to insert into two tables, users and email:

Table: users<records of users>...Table: emails<record of emails>...

Appendix AShell Utility Commands

A-6

Page 158: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

The imported records can be either in JSON or CSV format. If you do not specify theformat, JSON is assumed.

load

load -file <path to file>

Load the named file and interpret its contents as a script of commands to be executed.If any command in the script fails execution will end.

For example, suppose the following commands are collected in the script filetest.sql:

### Begin Script ###load -file test.ddlimport -table users -file users.json### End Script ###

Where the file test.ddl would contain content like this:

DROP TABLE IF EXISTS users;CREATE TABLE users(id INTEGER, firstname STRING, lastname STRING,age INTEGER, primary key (id));

And the file users.json would contain content like this:

{"id":1,"firstname":"Dean","lastname":"Morrison","age":51}{"id":2,"firstname":"Idona","lastname":"Roman","age":36}{"id":3,"firstname":"Bruno","lastname":"Nunez","age":49}

Then, the script can be run by using the load command in the shell:

> java -jar KVHOME/lib/sql.jar -helper-hosts node01:5000 \-store kvstoresql-> load -file ./test.sqlStatement completed successfully.Statement completed successfully.Loaded 3 rows to users.

mode

mode [COLUMN | LINE | JSON [-pretty] | CSV]

Sets the output mode of query results. The default value is JSON.

For example, a table shown in COLUMN mode:

sql-> mode column;sql-> SELECT * from users; +-----+-----------+-----------+-----+

Appendix AShell Utility Commands

A-7

Page 159: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| id | firstname | lastname | age | +-----+-----------+-----------+-----+ | 8 | Len | Aguirre | 42 | | 10 | Montana | Maldonado | 40 | | 24 | Chandler | Oneal | 25 | | 30 | Pascale | Mcdonald | 35 | | 34 | Xanthus | Jensen | 55 | | 35 | Ursula | Dudley | 32 | | 39 | Alan | Chang | 40 | | 6 | Lionel | Church | 30 | | 25 | Alyssa | Guerrero | 43 | | 33 | Gannon | Bray | 24 | | 48 | Ramona | Bass | 43 | | 76 | Maxwell | Mcleod | 26 | | 82 | Regina | Tillman | 58 | | 96 | Iola | Herring | 31 | | 100 | Keane | Sherman | 23 | +-----+-----------+-----------+-----+ ...

100 rows returned

Empty strings are displayed as an empty cell.

sql-> mode column;sql-> SELECT * from tab1 where id = 1; +----+------+----+------+ | id | s1 | s2 | s3 | +----+------+----+------+ | 1 | NULL | | NULL | +----+------+----+------+

1 row returned

For nested tables, identation is used to indicate the nesting under column mode:

sql-> SELECT * from nested;+----+-------+------------------------------------------------------------+| id | name | details |+----+-------+------------------------------------------------------------+| 1 | one | address || | | city | Waitakere || | | country | French Guiana || | | zipcode | 7229 || | | attributes || | | color | blue || | | price | expensive || | | size | large || | | phone | [(08)2435-0742, (09)8083-8862, (08)0742-2526]|+----+-------+------------------------------------------------------------+| 3 | three | address || | | city | Viddalba || | | country | Bhutan || | | zipcode | 280071 |

Appendix AShell Utility Commands

A-8

Page 160: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

| | | attributes || | | color | blue || | | price | cheap || | | size | small || | | phone | [(08)5361-2051, (03)5502-9721, (09)7962-8693]|+----+-------+------------------------------------------------------------+...

For example, a table shown in LINE mode, where the result is displayed vertically andone value is shown per line:

sql-> mode line;sql-> SELECT * from users;

> Row 1 +-----------+-----------+ | id | 8 | | firstname | Len | | lastname | Aguirre | | age | 42 | +-----------+-----------+

> Row 2 +-----------+-----------+ | id | 10 | | firstname | Montana | | lastname | Maldonado | | age | 40 | +-----------+-----------+

> Row 3 +-----------+-----------+ | id | 24 | | firstname | Chandler | | lastname | Oneal | | age | 25 | +-----------+-----------+ ...100 rows returned

Just as in COLUMN mode, empty strings are displayed as an empty cell:

sql-> mode line;sql-> SELECT * from tab1 where id = 1;

> Row 1 +---------+------+ | id | 1 | | s1 | NULL | | s2 | | | s3 | NULL | +---------+------+

Appendix AShell Utility Commands

A-9

Page 161: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

1 row returned

For example, a table shown in JSON mode:

sql-> mode json;sql-> SELECT * from users;{"id":8,"firstname":"Len","lastname":"Aguirre","age":42}{"id":10,"firstname":"Montana","lastname":"Maldonado","age":40}{"id":24,"firstname":"Chandler","lastname":"Oneal","age":25}{"id":30,"firstname":"Pascale","lastname":"Mcdonald","age":35}{"id":34,"firstname":"Xanthus","lastname":"Jensen","age":55}{"id":35,"firstname":"Ursula","lastname":"Dudley","age":32}{"id":39,"firstname":"Alan","lastname":"Chang","age":40}{"id":6,"firstname":"Lionel","lastname":"Church","age":30}{"id":25,"firstname":"Alyssa","lastname":"Guerrero","age":43}{"id":33,"firstname":"Gannon","lastname":"Bray","age":24}{"id":48,"firstname":"Ramona","lastname":"Bass","age":43}{"id":76,"firstname":"Maxwell","lastname":"Mcleod","age":26}{"id":82,"firstname":"Regina","lastname":"Tillman","age":58}{"id":96,"firstname":"Iola","lastname":"Herring","age":31}{"id":100,"firstname":"Keane","lastname":"Sherman","age":23}{"id":3,"firstname":"Bruno","lastname":"Nunez","age":49}{"id":14,"firstname":"Thomas","lastname":"Wallace","age":48}{"id":41,"firstname":"Vivien","lastname":"Hahn","age":47}...100 rows returned

Empty strings are displayed as "".

sql-> mode json;sql-> SELECT * from tab1 where id = 1;{"id":1,"s1":null,"s2":"","s3":"NULL"}

1 row returned

Finally, a table shown in CSV mode:

sql-> mode csv;sql-> SELECT * from users;8,Len,Aguirre,4210,Montana,Maldonado,4024,Chandler,Oneal,2530,Pascale,Mcdonald,3534,Xanthus,Jensen,5535,Ursula,Dudley,3239,Alan,Chang,406,Lionel,Church,3025,Alyssa,Guerrero,4333,Gannon,Bray,2448,Ramona,Bass,4376,Maxwell,Mcleod,2682,Regina,Tillman,58

Appendix AShell Utility Commands

A-10

Page 162: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

96,Iola,Herring,31100,Keane,Sherman,233,Bruno,Nunez,4914,Thomas,Wallace,4841,Vivien,Hahn,47...100 rows returned

Like in JSON mode, empty strings are displayed as "".

sql-> mode csv;sql-> SELECT * from tab1 where id = 1;1,NULL,"","NULL"

1 row returned

Note:

Only rows that contain simple type values can be displayed in CSV format.Nested values are not supported.

output

output [stdout | file]

Enables or disables output of query results to a file. If no argument is specified, itshows the current output.

page

page [on | <n> | off]

Turns query output paging on or off. If specified, n is used as the page height.

If n is 0, or "on" is specified, the default page height is used. Setting n to "off" turnspaging off.

show faults

show faults [-last] [-command <index>]

Encapsulates commands that display the state of the store and its components.

show namespaces

show [AS JSON] namespaces

Appendix AShell Utility Commands

A-11

Page 163: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Shows a list of all namespaces in the system.

For example:

sql-> show namespacesnamespaces ns1 sysdefaultsql-> show as json namespaces{"namespaces" : ["ns1","sysdefault"]}

show query

show query <statement>

Displays the query plan for a query.

For example:

sql-> show query SELECT * from Users;RECV([6], 0, 1, 2, 3, 4)[ DistributionKind : ALL_PARTITIONS, Number of Registers :7, Number of Iterators :12, SFW([6], 0, 1, 2, 3, 4) [ FROM: BASE_TABLE([5], 0, 1, 2, 3, 4) [Users via primary index] as $$Users

SELECT: * ]]

show roles

show [as json] roles | role <role_name>

Shows either all the roles currently defined for the store, or the named role.

show tables

show [as json] {tables | table table_name}

Shows either all tables in the data store, or one specific table, table_name.

Specify a fully-qualified table_name as follows:

Appendix AShell Utility Commands

A-12

Page 164: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

Entry specification Description

table_name Required. Specifies the full table name. Withoutfurther qualification, this entry indicates a tablecreated in the default namespace (sysdefault),which you do not have to specify.

parent-table.child-table Specifies a child table of a parent. Specify theparent table followed by a period (.) before the childname. For example, if the parent table is Users,specify the child table named MailingAddress asUsers.MailingAddress.

namespace-name:table-name Specifies a table created in the non-defaultnamespace. Use the namespace followed by acolon (:). For example, to reference table Users,created in the Sales namespace, enter table_nameas Sales:Users.

The following example indicates how to list all tables, or just one table. The emptytableHierarchy field indicates that table t1 was created in the default namespace:

sql-> show tablestables SYS$IndexStatsLease SYS$PartitionStatsLease SYS$SGAttributesTable SYS$TableStatsIndex SYS$TableStatsPartition ns10:t10 parent parent.child sg1 t1

sql-> show table t1tableHierarchy t1

To show a table created in a namespace, as shown in the list of all tables, fully-qualifytable_name as follows. In this case, tableHierarchy field lists namespace ns1 inwhich table t1 was created. The example also shows how the table is presented asjson:

sql-> show tables;tables SYS$IndexStatsLease SYS$PartitionStatsLease SYS$SGAttributesTable SYS$TableStatsIndex SYS$TableStatsPartition ns1:foo ns1:t1

Appendix AShell Utility Commands

A-13

Page 165: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

sql-> show table ns1:t1;tableHierarchy(namespace ns1) t1sql-> show as json table ns1:t1;{"namespace": "ns1""tableHierarchy" : ["t1"]}

show users

show [as json] users | user <user_name>

Shows either all the users currently existing in the store, or the named user.

timeout

timeout [<timeout_ms>]

Configures or displays the request timeout for this session. If not specified, it showsthe current value of request timeout.

timer

timer [on | off]

Turns the measurement and display of execution time for commands on or off. If notspecified, it shows the current state of timer. For example:

sql-> timer onsql-> SELECT * from users where id <= 10 ; +----+-----------+-----------+-----+ | id | firstname | lastname | age | +----+-----------+-----------+-----+ | 8 | Len | Aguirre | 42 | | 10 | Montana | Maldonado | 40 | | 6 | Lionel | Church | 30 | | 3 | Bruno | Nunez | 49 | | 2 | Idona | Roman | 36 | | 4 | Cooper | Morgan | 39 | | 7 | Hanae | Chapman | 50 | | 9 | Julie | Taylor | 38 | | 1 | Dean | Morrison | 51 | | 5 | Troy | Stuart | 30 | +----+-----------+-----------+-----+

10 rows returned

Time: 0sec 98ms

Appendix AShell Utility Commands

A-14

Page 166: Getting Started with SQL for Oracle NoSQL Database · Introduction to SQL for Oracle NoSQL Database Welcome to SQL for Oracle NoSQL Database. This language provides a SQL-like interface

verbose

verbose [on | off]

Toggles or sets the global verbosity setting. This property can also be set on a per-command basis using the -verbose flag.

version

version

Display client version information.

Appendix AShell Utility Commands

A-15