« Back to the developer homepage
MotorsportQL: Motorsport Query Language
Martin Galpin (m@66laps.com)
Introduction
Motorsport Query Language (known as MotorsportQL) is a small query language for retrieving motorsport telemetry stored in a database. It has a simple, SQL-like syntax.
The primary purpose of MotorsportQL is to quickly perform relational queries on a database of motorsport telemetry without the need to understand its particular storage implementation.
For example, MotorsportQL makes it easy to perform simple queries such as:
select fastest where venue.name = "Silverstone" and vehicle.category = "Formula One" and datetime < '2010-01-01' and (user = "Michael Schumacher" or user = "Nico Rosberg")
A reference MotorsportQL parser is provided under the terms of the GNU General Public License v3. For more information see python-motorsportql.
The examples shown below give examples of valid MotorsportQL statements. The response format is beyond the specification of this document and it is left to the implementation to decide on the most appropriate format.
For example, a RESTful web service would probably return responses as JSON formatted arrays. Other implementations may prefer to return results in another format, such as domain specific objects (see python-openmotorsport).
select statement
A select statement retrieves laps from the database.
Synopsis
select_command ::= "select" ("*" | context_clause | comparison_clause) [where_clause] [order_clause] [limit_clause] ;
Description
A select statement returns candidate laps from a database that
satisfy an optional where clause. If a where clause is omitted then all
laps are considered candidates.
Results can be further reduced using either a context or comparison clause.
Alternatively, if an asterisk (*) is given, all matching candidate laps will
be returned.
The context and comparison clauses provide a shorthand notation to common queries.
Context clause
context_clause ::= ("fastest" | "slowest") [ "," context_clause ] ;
The context clause provides a shorthand notation to retrieve the fastest or slowest lap within a list of candidate laps.
Multiple superlatives may be given and the order of which is not significant. However, a context is considered definitive and therefore a maximum of one lap will be returned for each context.
Examples
Find the fastest lap by Michael Schumacher:
select fastest where user = "Michael Schumacher"
Find the slowest lap at Silverstone by Nico Rosberg:
select slowest where venue.name = "Silverstone" and user = 'Nico Rosberg'
Find the fastest and slowest lap at Silverstone in a Formula One car:
select fastest, slowest where venue.name = "Silverstone" and vehicle.category = "Formula One"
Comparison clause
comparison_clause ::= ( "faster" | "slower" ) "than" lap_def ;
The comparison clause provides a shorthand notation to further reduce candidate laps relative to a given lap.
Only a single comparative can be given in each query and must be followed by than
and lap_def.
lap_def is a integral session identifier followed a period and an integral
lap index (starting at 0). It is defined as:
lap_def ::= session_id "." lap_index ; session_id ::= digit_def+ ; lap_index ::= digit_def+ ; digit_def ::= [0-9]+
It could be said that lap_def is coupling MotorsportQL to a
particular storage implementation (one that relies of a integral session
identifier). Indeed, this seemingly violates the original raison
d'ĂȘtre of the language. It is therefore suggested that any MotorsportQL
implementation abstract lap_def in a manor consistent with its own API.
Examples
Find laps faster than the second lap in session 66 by Michael Schumacher:
select faster than 66.1 where user = 'Michael Schumacher'
Find laps slower than the eleventh lap in session 1066 in a vehicle
before the year 2010:
select slower than 1066.10 where vehicle.year < 2010
where clause
where_clause ::= "where" condition_def { logical_set condition_def } ; condition_def ::= ( (comparator_set binary_operator_set quoted_string) | (function_name "(" delimeted_quoted_string ")") ) ; quoted_string_def ::= [a-zA-Z0-9]+ ; delimeted_quoted_string_def ::= quoted_string_def { "," delimeted_quoted_string_def }
The optional where clause provides a familiar notation for reducing candidate
laps by matching a sequence of boolean expressions.
The most common form of expression is:
comparator binary_operator quoted_string
A comparator is defined for every metadata field declared in the OpenMotorsport file format. See the OpenMotorsport specification for more information.
A binary_operator can be any of: = != < > <= => or a conditional operator
such as like. The right hand side of an expression should be properly enclosed
in quotes using either " or '.
Multiple expressions may be separated by the logical operators and or and
expressions can be nested within parentheses. The traditional order of
precedence is applied (and is evaluated before or).
Comparators
A list of valid comparators is as follows:
| Comparator | Description |
|---|---|
lap.length |
The lap time in milliseconds. |
lap.index |
The lap index (starting at 0). |
user |
The name of the user who recorded the session. See //openmotorsport/metadata/user. |
vehicle.name |
The name of the vehicle. See //openmotorsport/metadata/vehicle/name. |
vehicle.category |
The vehicle category (e.g. Formula One). See //openmotorsport/metadata/vehicle/category. |
vehicle.comments |
Comments about this vehicle. See //openmotorsport/metadata/vehicle/comments. |
vehicle.year |
The year this vehicle was manufactured. See //openmotorsport/metadata/vehicle/year. |
venue.name |
The name of this venue (e.g. Silverstone). See //openmotorsport/metadata/venue/name. |
venue.configuration |
The name the track configuration (e.g. Grand Prix). See //openmotorsport/metadata/venue/configuration. |
datetime |
The date and time of this session. Exposed via a single string of the form YYYY-MM-DD HH:MM. See //openmotorsport/metadata/date. |
duration |
The total duration of this session in milliseconds. See //openmotorsport/metadata/duration. |
comments |
Comments about this session. See //openmotorsport/metadata/comments. |
datasource |
The recording datasource (e.g. logger number, simulator). See //openmotorsport/metadata/datasource. |
Examples
Find the fastest lap in a Formula One car made before 2010, driven by Nico Rosberg.
select fastest where vehicle.year < 2010 and user = 'Nico Rosberg' and vehicle.category = "Formula One"
Find a lap faster and slower than the second lap of session id 66, before June 22th 2009.
select faster than 66.1 where datetime < '2009-06-22' and (user = 'Rubens Barrichello' or 'Jenson Button')
Find laps with a lap time faster or equal to 137.121 seconds (analogous to a
faster clause).
select * where lap.length < 137121
Functions
MotorsportQL also exposes the following functions for use as boolean
conditions in a where clause:
| Function | Description |
|---|---|
haschannel(name, name, ...) |
This function returns true if the current session contains channels by the given name. Otherwise, false. |
Examples
Find all laps with a channel called Acceleration X.
select * where haschannel('Acceleration X')
Find all laps with the channels Throttle Position and Brake Position, at Donington Park.
select * where (venue.name = 'Donington Park' and haschannel("Throttle Position", "Brake Position"))
order by clause
order_clause ::= "order" "by" sort_by_def { "," sort_by_def } ; sort_by_def ::= comparator_set [ "asc" | "desc " ] ;
The order by clause sorts results by an arbitrary number of comparators in
either ascending (lowest to highest) or descending order (highest to lowest).
If no explicit order is given, results will be ordered according to the following logic.
For faster queries, results will be ordered in ascending lap.length,
such that the fastest lap is returned first. Conversely, slower comparisons
will be ordered in descending lap.length such that the slowest lap is
returned first.
For queries that include a fastest and a slowest context, the order of the
results will correspond to the order of the contexts.
For all other queries, if no explicit order is given, results will be in
ascending lap.length such that the fastest lap is returned first.
Examples
Find all laps from Brands Hatch, ordered by descending lap time (slowest first).
select * where venue.name = "Brands Hatch" order by lap.length desc
Find all laps in lexicographically ascending user order.
select * order by user
limit clause
limit_clause ::= "limit" digit_def+ ["," digit_def+] ;
The limit clause allows queries to return results up to a given maximum,
starting at an optional offset.
When a single argument is given, it denotes the maximum number of results to return. Otherwise, if two arguments are given (separated by a comma), the first specifies the offset of the first lap whilst the second continues to denote the maximum number of results.
Examples
Find all laps up to a maximum of 100.
select * limit 100
Find a maximum of 25 laps by a Schumacher starting at lap 66.
select * limit 66, 25
Appendix A: EBNF Grammar
The following represents a complete Extended Backus-Naur Form (EBNF) definition of MotorsportQL.
NB: MotorsportQL is not case sensitive but for the sake of simplicity, the following grammar only presents rules in lower case.
select_command ::= "select" ("*" | context_clause | comparison_clause) [where_clause] [order_clause] [limit_clause] ; context_clause ::= ("fastest" | "slowest") [ "," context_clause ] ; comparison_clause ::= ( "faster" | "slower" ) "than" lap_def ; where_clause ::= "where" condition_def { logical_set condition_def } ; limit_clause ::= "limit" digit_def ["," digit_def] ; order_clause ::= "order" "by" sort_by_def { "," sort_by_def } ; sort_by_def ::= comparator_set [ "asc" | "desc " ] ; condition_def ::= ( (comparator_set binary_operator_set quoted_string) | (function_name "(" delimeted_quoted_string ")") ) ; binary_operator_set ::= "=" | "!=" | "<" | "<=" | ">" | ">=" ; logical_set ::= "and" | "or" ; (* A comparator for every field in the OpenMotorsport "metadata" element. *) comparator_set ::= "lap.length" | "lap.index" | "user" | "vehicle.name" | "vehicle.category" | "vehicle.year" | "vehicle.comments" | "venue.name" | "venue.configuration" | "datetime" | "duration" | "comments" | "datasource" ; lap_def ::= session_id "." lap_index ; session_id ::= digit_def ; lap_index ::= digit_def ; quoted_string_def ::= [a-zA-Z0-9]+ ; delimeted_quoted_string_def ::= quoted_string_def { "," delimeted_quoted_string_def } function_name_def ::= [a-zA-Z]+ ; digit_def ::= [0-9]+ ;
Appendix B: Reference implementations
The following libraries implements the MotorsportQL specification:
- Python (Apache License Version 2.0)
Appendix C: Version History
| Date | Version | History |
|---|---|---|
| 27/09/2010 | 1.0 | Initial release |
Appendix D: License
Copyright © 2010 66laps Limited.