ExamplesThe following are some examples of JoSQL usage. As you go further down the page, the more complex the examples become. For all of the examples, the object used is
java.io.File
. To start with though, here is the basic usage from Java.
List myObjs = getMyObjects ();
Query q = new Query ();
q.parse (sql);
QueryResults qr = q.execute (myObjs);
List res = qr.getResults ();
Sections
Basic Where Clauses
The following is about the simplest form you can use, just select some Files with names ending in
.java.
SELECT *
FROM java.io.File
WHERE name LIKE '%.java'
This simple case will return all the matching files that have a filename ending with
.java. Easy ;)
This time return specific information from the File object (the name and length), for the Files with names ending in
.java.
SELECT name,
length
FROM java.io.File
WHERE name LIKE '%.java'
Now, the results will be a
List of
Lists. Each List will contain 2 values, index 0 will be a String (the name of the file), index 1 will be a Number (the length of the file).
Complex Where Clause
This time return specific information from the File object (the name and length), for the Files with names ending in
.java and have been modified between
10/10/2000 and
10/10/2001 and are
src directories.
SELECT name,
length
FROM java.io.File
WHERE name LIKE '%.java'
AND lastModified BETWEEN toDate ('10-10-2000') AND toDate ('10-10-2001')
AND parent LIKE '%src%'
Again, the results will be a
List of
Lists. Each List will contain 2 values, index 0 will be a String (the name of the file), index 1 will be a Number (the length of the file). JoSQL uses lazy-evaluation in the WHERE clause so it is better to put clauses that are likely to limit the results most near the top. In this case the clause checking the parent path is probably best off being moved up since it will prevent non
src directories from being searched. Notice here that we also make use of the function:
toDate to convert the string representation of the date to a
java.util.Date object.
Bind Variables
This time return specific information from the File object (the name and length). In this case for the WHERE clause we use
bind variables to specify the values instead of hard-coding them in the query.
SELECT name,
length
FROM java.io.File
WHERE name LIKE :fileExt
AND lastModified BETWEEN :fromDate AND :toDate
AND parent LIKE :path
Notice here that for the date used in the
BETWEEN clause there is no need to perform a conversion. JoSQL supports Java objects directly, conversion is only generally required when you need to convert from one format to another, for example a string representation to a date.
In this case the bind variables need to be specified in the Query object prior to executing the query, this can be performed thus:
q.setVariable ("fileExt",
"%.java");
SimpleDateFormat sdf = new SimpleDateFormat ("dd-MM-yyyy");
q.setVariable ("fromDate",
sdf.parse ("10-10-2000"));
q.setVariable ("toDate",
sdf.parse ("10-10-2001"));
q.setVariable ("path",
"%src%");
QueryResults res = q.execute (myFiles);
It should be noted here that those bind variables will remain in the Query object until they are either cleared. This means that you can set them once and then re-execute the query.
Functions
This time return specific information from the File object (the name and length), but process the values with
functions first, also use functions in the WHERE clause.
SELECT upper (fileExtension (name)),
formatNumber (length),
formatDateTime (lastModified),
formatDateTime (parentFile.lastModified)
formatTimeDuration (lastModified - parentFile.lastModified)
FROM java.io.File
WHERE lower (name) LIKE lower (:fileExt)
AND toDate (lastModified) BETWEEN :fromDate AND :toDate
AND upper (parent) LIKE upper (:path)
Starting to get a little more complex here ;) But still pretty simple, note the use of functions in both the SELECT and WHERE clauses. Functions can basically be used everywhere. You can use any function in the SELECT clause but be aware of performance issues since JoSQL
DOES NOT perform caching of function return values (to minimize performance implications use the
EXECUTE ON clauses). It should be noted that the use of the
lower and
upper functions here can be re-worked to use the
$LIKE operator instead which will perform a case-insensitive comparison instead.
Execute On Clauses
This example uses
EXECUTE ON clauses. These clauses allow a number of functions to be defined that should be executed a specific number of times (usually once) at specific points in the
execution of the statement and the values returned from the functions saved in
save values. Once these functions have been executed the saved values are then available for use in the rest of the statement by using a
@ prefix. Thus:
SELECT @maxLength,
formatNumber (@avgLength),
formatDate (@newest),
@mostFiles.name
FROM java.io.File
EXECUTE ON ALL max (:_allobjs, length) maxLength,
avg (:_allobjs, length) avgLength,
max (:_allobjs, lastModified) newest,
maxObject (:_allobjs, parentFile.listFiles.length) mostFiles
Each of the functions listed in the
EXECUTE ON ALL clause is executed once during execution for all the File objects. As can be seen, the save values can then be manipulated via functions as well and can in fact then
accessors associated with them as with the
maxObject function which in this case will return the directory that has the most files in it.
Now one further note here, because JoSQL does not have the "normal" concept (used by RDBMSs) of grouping it means that in this case that there will be as many results as there are input objects. However this is generally not desirable, so to prevent this, the
LIMIT clause should be used thus:
Which in this case means, only return a single row, starting at row 1.
Order By
This example provides sorting of a statement, notice that functions, expressions and save values can be used as sort criteria.
SELECT *
FROM java.io.File
ORDER BY upper (name) DESC, length > @avgLength
EXECUTE ON ALL avg (:_allobjs, length) avgLength
It is also possible to sort on a column in the SELECT clause (Note: in which case, one or more columns must be selected).
SELECT name,
length
FROM java.io.File
ORDER BY 1 DESC, 2 DESC
EXECUTE ON ALL avg (:_allobjs, length) avgLength
Of course when sorting on columns indices you can't use a function (for what should be pretty obvious reasons! If the reason isn't obvious then consider the following
ORDER BY upper (2), in this case the parser must take the
2 as a numeric literal rather than a column index).
Grouping
One significant different between JoSQL's use of SQL and standard (ANSI) SQL used by RDBMSs is in respect to grouping of data. Since JoSQL has the full power of the Java collections framework available it allows the grouping data AND the items that correspond to that grouping (key) available as well. In practice this is effectively like placing items into a Map with the
GROUP BY clause providing a multi-column "key" and the
SELECT clause providing a List of objects that map to that key. For example to group on the parent directory, i.e. return all files in each directory:
SELECT *
FROM java.io.File
GROUP BY parent
GROUP BY ORDER parent
ORDER BY name DESC, length DESC
It should be noted here that the
GROUP BY columns can be sorted as well by using the
GROUP BY ORDER clause. The
ORDER BY clause is then used to sort the results of each List.
To use in Java code:
QueryResults res = q.execute (myFiles);
Map grpBys = res.getGroupByResults ();
Iterator iter = grpBys.keySet ().iterator ();
while (iter.hasNext ())
{
List key = (List) iter.next ();
List res = (List) grpBys.get (key);
}
Putting it all together
So, let's solve a real (well potentially real ;) problem.
Let's get ALL Java files from a particular set of files, group them by directory, only return those greater than 10K in size, order the files by file size, then name, order the directories by the last time they were modified. Also, let's work out some overall statistics about the files in each directory, the average file size, the file that was modified last, the smallest file and for each directory how many Java files are in the directory. Here goes!
SELECT *
FROM java.io.File
WHERE name LIKE :fileType
AND length > (:kbsize * 1024)
GROUP BY parent
GROUP BY ORDER lastModified
ORDER BY length, name
EXECUTE ON GROUP_BY_RESULTS avg (length) avgLength,
minObject (:_allobjs, lastModified) lastModified,
minObject (:_allobjs, length) smallest,
accessor (:_allobjs, "size") count
Just so you know, JoSQL does have lots more functionality than this but hopefully this has provided a good enough "taster" to get you started! If you have any further questions please don't hesitate to
contact me for assistance.
© Gary Bentley 2004-2007. All Rights Reserved.