OQL - Object Query Language
The goal of this file is to help you get started with OQL. The examples presented in this file refer to classes defined in the file "O2 Tutorial".
Please note that the syntax in some of the examples might need minor adjustment before they will work with the current version of O2. If you find any errors, or places which are unclear, or if you have any suggestions or comments, please let us know (email to Michael - mpetropo@cs.ucsd.edu). Your help is greatly appreciated.
Introduction
OQL is the way to access data in an O2 database. OQL is a powerful and easy-to-use SQL-like query language with special features dealing with complex objects, values and methods.
Using OQLWe've been able to create classes and write some programs. So far, O2 appears to be like an object-oriented programming language like C++ instead of a database system. Probably the main difference is that O2 supports queries. The queries that you'll be creating will look very similar to that of SQL.
In order to perform queries, you'll need to enter query mode. From within the O2 client, do the command:
SELECT <list of values>
FROM <list of collections and variable
assignments>
WHERE <condition>
The SELECT clause extracts those elements of a collection meeting a specific condition. By using the keyword DISTINCT duplicated elements in the resulting collection get eliminated. Collections in FROM can be either extents (persistent names - sets) or expressions that evaluate to a collection (a set). Strings are enclosed in double-quotes in OQL. We can rename a field by if we prefix the path with the desired name and a colon.
Example Query 1
Give the names of people who are older than 26
years old:
SELECT SName:
p.name
FROM p in
People
WHERE p.age > 26
(hit Ctrl-D)
Dot Notation & Path Expressions
We use the dot notation and path expressions to access
components of complex values.
Let variables t and ta range over
objects in extents (persistent names) of Tutors and TAs (i.e., range over
objects in sets Tutors and TAs).
ta.salary ->
real
t.students -> set of tuples of type tuple(name: string,
fee: real) representing students
t.salary -> real
Cascade of dots can be used if all names represent objects and not a collection.
Example of Illegal Use of Dot
t.students.name, where ta is a TA object.
This is illegal, because ta.students is a set of objects, not a single object.
Example Query 2
SELECT s.name
FROM Tutors t, t.students
s
Here we notice that the variable t that binds to the first collection of FROM is used to help us define the second collection s. Because students is a collection, we use it in the FROM list, like t.students above, if we want to access attributes of students.
Example Query 3
Give
the names of the Tutors which have a salary greater than $300
and have a student paying more than $30:
SELECT t.name
FROM ( SELECT t
FROM Tutors t WHERE t.salary > 300 ) r, r.students
s
WHERE s.fee > 30
Example Query 4
Give
the names of people who aren't TAs:
SELECT p.name
FROM p in
People
WHERE not ( p.name in SELECT t.name FROM t in TAs
)
Set Operations and Aggregation
The standard O2C
operators for sets are + (union), * (intersection),
and - (difference). In OQL, the operators are written as
UNION, INTERSECT and EXCEPT
, respectively.
Example Query 5
Give
the names of TAs with the highest salary:
SELECT t.name
FROM t in TAs
WHERE
t.salary = max ( select ta.salary from ta in TAs )<
/FONT >
The GROUP BY operator creates a set of tuples with two fields. The first has the type of the specified GROUP BY attribute. The second field is the set of tuples that match that attribute. By default, the second field is called PARTITION.
Example Query 6
Give the names of the students and the average
fee they pay their Tutors:
SELECT sname, avgFee: AVG(SELECT p.s.fee FROM
partition p)
FROM t in Tutors,
t.students s< BR > GROUP BY sname: s.name<
/FONT >
1. Initial collection
We begin from collection Tutors, but technically it is a bag of tuples of the form:
tuple(t: t1, s: tuple(name: string, fee: real) )
where t1 is a Tutor object and s denotes a student tuple. In general, there are fields for all of the variable bindings in the FROM clause.
2. Intermediate collection
The GROUP BY attribute s.name maps the tuples of the initial collection to the value of the name of the student. The intermediate collection is a set of tuples of type:
tuple( sname: string, partition: set( tuple(t: Tutor, s: tuple( name: string, fee: real ) ) ) )
For example:
tuple( sname = "Mike", partition = set( tuple(t1, tuple( "Mike", 10 ) ), tuple(t2, tuple( "Mike", 20 ) ) ) )
where t1,t2,... are all the tutors of student "Mike".
3. Output collection
Consists of student-average fee pairs, one for each tuple in the intermediate collection. The type of tuples in the output is:
tuple(sname: string, avgFee: real)
Note that in the subquery of the SELECT clause:
SELECT sname, avgFee: AVG(SELECT p.s.fee FROM partition p)
We let p range over all tuples in partition. Each of these tuples contains a Tutor object and a student tuple. Thus, p.s.fee extracts the fee from one of the student tuples.
A typical output tuple looks like this:
tuple(sname = "Mike", avgFee = 15)
The whole procedure of GROUP BY operator's evaluation is summarized in the following figure:
Instead of using query mode, you can incorporate these queries in your O2
programs using the "o2query" command:
run body {
o2 real
total_salaries;
o2query( total_salaries, "sum ( SELECT
ta->get_salary \
FROM ta in TAs )" );
printf("TAs combined
salary: %.2f\n", total_salaries);
};
The first
argument for o2query is the variable in which you want to store the query
results. The second argument is a string that contains the query to be
performed. If your query string takes up several lines, be sure to
backslash (\) the carriage returns.
Change directory executing the following:
cd
/software/nonrdist/o2_5.0/manuals
You can access the OQL User Manual by opening the following
file:
acroread oql.pdf