Skip to main content

Basic Constructs

The basic building blocks of the OSQL query language are described here.

The Read-Eval-Print-Loop

OSQL statements can be evaluated immediately by SA Engine through its OSQL Read-Eval-Print-Loop, REPL. When using the SA Engine Console REPL in Unix/Windows shells, OSQL statements must be terminated by a semicolon (;). The ; is not needed when evaluating a single statement to the REPL in your browser or in SA Studio.

Example:

1+2+3

You can enter more than one statement to the REPL by separating them with a ;.

Examples:

"Hello" + " world";
sin(4) + sqrt(9) * 2;
rand(100)+1

Constants

Constants can be integers, reals, strings, time stamps, booleans, or null. The value of a constant is the constant itself.

Examples: of constant numbers:

123
1.2
2.3E2
-2.4e-21

Examples of constant strings:

"A string"
'A string'
'A string with "'
"A string with \" and '"

The enclosing string separators (' or ") for a string constant must be the same. If the string separator is " then \ is the escape character inside the string, replacing the succeeding character. For example the string 'ab"\' can also be written as "ab\"\\", and the string a'"b must be written as "a'\"b".

Example of a constant time stamp:

|2025-11-18T12:27:43.985Z|

Boolean constants represent logical values. The constant false is equivalent to null casted to type Boolean. The only legal boolean value that can be stored in the database is true.

There are two boolean constants:

true
false

A boolean value is regarded as false if it is null or not in the database (so called close world assumption).

null

Identifiers

Identifiers represent names of OSQL variables, functions, arrays, etc. For exampe, MySalary, sin, Integer, x, x1234, or x1234_b. Notice that OSQL identifiers are not case sensitive; i.e. they are always internally capitalized.

Comments

A comment enclosed with /* and */can be placed anywhere in an OSQL statement outside identifiers, constants, strings, or variables. You can also use SQL's single line comments:

-- This is a comment

Variables

Variables are of two kinds: local variables and session variables.

Local variables are identifiers for data values inside OSQL queries and functions. Variables are not case sensitive and internally capitalized.

Example: the following query uses a local variable named I:

select i
from Number i
where I = 3

Local variables must be declared in from clauses of queries or function signatures (see Functions).

Session variables are prefixed with :, e.g.:x, :my_stream, etc. They hold only temporary results during interactive sessions. Session variables cannot be referenced in function bodies and they are not stored in the database. Their lifespan is the current session only. Their purpose is to hold temporary values in scripts and database interactions.

Session variables can be assigned by the variable assignment statement set.

Examples: these statements assign values to the session variables :x, :i, and :v:

set :x = sqrt(2)        -- set session variable :x3
set :i = round(3.5)     -- set session variable :i
set :v = [1,2,3]        -- set session variavle :v

These expresson gets the values of the assignments:

:x3                    -- get value of :x3
:i                     -- get value of :i
:V                     -- get value of :v

You can inspect the type signature of the value to which a variable is assigned by the function typesig(Object).

Examples:

typesig(:x3)
typesig(:i)
typesig(:v)

Expressions

Expressions are formulas expressed with the OSQL syntax that can be evaluated by the REPL to produce a value. Complex expressions can be built up in terms of other expression. Expressions are basic building blocks in all kinds of OSQL statements.

Examples:

1+2+3
[1,2,3]+1
1+array([[1,2],[3,4]])

Entering simple expressions is the simplest form of OSQL queries.

Tuples

Tuples group several comma separated values eie_i using the notation (e1,e2,...)(e_1, e_2,...).

Examples:

('a',1);
('a',1.1,2)

A tuple with a single element, a singelton, is the same as the element itself:

('a')

Collections

Collections represent sets of objects. OSQL supports five kinds of collections: bags, vectors, arrays, streams, and key-value associations (records):

  • A bag is a set where duplicates are allowed.
  • A vector is an ordered sequence of objects of any kind.
  • A record is an associative array of key-value pairs.
  • An array is a multi-dimensional collection of numbers.
  • A stream is a possibly infinite sequence of objects that is continuously extended with new elements at the end.

Collections are constructed by collection constructor expressions.

Examples:

Construct a bag of numbers:

values 1,2,3

Construct a vector of numbers:

[1,2,3]

Construct a vector of vectors of numbers:

[[1,2],[3,4]]

Construct a bag of vectors:

values ['a',1],['b',2],['c',3]

Construct a record (JSON object):

{"id":1,"name":"Kalle","age":32}

Construct an array of integers:

array([1,2,3])

Bags

A common kind of collection is bags, which are unordered sets of objects with duplicates allowed. The value of a query is usually a bag. When a query to an SA Engine REPL returns a bag as result the elements of the bag are printed on separate lines.

Bags can be explicitly created using the values v1,v2,.. notation.

Example:

   values 1,2,2,3

A bag containing a single values is equivalent to the single value itself.

Example:

values 1

Tuples in values expressions construct bags of tuples. Nameless constant tables are represented as a bag of tuples having the same lengths and types. This bag represents a table with two columns typed `Charstring and Integer.

 values ('a',1),('b',2),('c',3)
typesig(values ('a',1),('b',2),('c',3)) 

A bag of singeltons represents a nameless table with one column:

values ('a'),('b'),('c')
typesig(values ('a'),('b'),('c'))

The (values v1,v2....) notation can be used to represent bags inside other expressions.

Example:

 select i+1 
from Integer i
where i in (values 3,4,2)

Vectors

Vectors are sequences of elements of the same type. Square brackets [] enclose vector elements. Vectors are represented as objects of type Vector.

Example:

[1,2,3]
typesig([1,2,3])

Vector element viv_i can be accessed with the notation v[i], where the indexing i is from 1 and up.

Example:

set :v = [1,2,3]
:v[3]

Section Vectors documents vector functions and queries.

Arrays

Multi-dimensional arrays represent collections of numbers. 1D arrays represent numerical vectors, 2D arrays represent numerical matrices, and higher dimensionality arrays represent tensors.

Arrays are represented as objects of type Array. The difference between objects of type Array and type Vector is that vectors represent 1D sequences of objects of any kind, while 1D arrays very efficiently represent numerical vectors.

Arrays create created with the function array():

Examples:

A numerical vector of integers:

array([1,2,3])

A numerical vector of reals:

array([1.1,2.2,3.3])

A 3x2 matrix of integers with 3 columns and 2 rows:

array([[1,2,3],[3,4,5]])

A 3x2 matrix of reals:

array([[1.1,2.2,3.3],[3,4,5]])

Section Arrays and tensors documents array functions and queries.

Records

Records represent dynamic associations between keys and values. A record is a dynamic and associative array. Other commonly used terms for associative arrays are JSON objects, property lists, key-value pairs, dictionaries, or hash links. OSQL uses JSON notation to construct records.

Example: the following expression assigns the session variable :r to a record where the key (property) 'Greeting' field has the value 'Hello, I am Tore' and the key 'Email' has the value 'Tore.Andersson@it.uu.se':

   set :r= {'Greeting':'Hello, I am Tore','Email':'Tore.Andersson@it.uu.se'};

A field f of a record bound to a variable r can be access with the notation r[f].

Example:

:r['Greeting' ]

The type of records is named Record. The type Json represents JSON data. It is above both types Record and Vector in the type hierarchy, since JSON representations include both JSON objects and vectors.

Streams

Streams represent possibly infinite and growing sequences of elements, such as measurements produced by a sensor. Streams can also be generated (simulated) by functions.

Example: The function heartbeat(p) returns an infinite stream of number elements produced every p seconds:

heartbeat(0.5) 

Streams are documented in section Streams.