Learning > ECSQL Edit this page ECSQL Make sure to check out the ECSQL Tutorial as well! What is ECSQL ECSQL is a text-based command language for CRUD (create, read, update, delete) operations against the business data in an iModel or ECDb file. ECSQL is an implementation of SQL — a proven, well-adopted text-based command language. It adheres to standard SQL (SQL-92 and SQL-99) wherever possible. Especially the SQL-99 standard came with a lot of features ECSchemas have too: boolean, date time, binary data types, structs, arrays, polymorphism. This allows ECSQL to deviate only in very few exceptions from standard SQL. Anyone familiar with SQL should intuitively understand ECSQL. The key difference between ECSQL and SQL is that ECSQL targets the logical schema, and not the underlying database’s persistence schema. ECSQL in detail This is not a comprehensive documentation of the SQL subset of ECSQL. This document only describes the exceptions to standard SQL and the cases where less known features of the standard are used. Standard SQL refers to SQL-92 (aka SQL 2), and to SQL-99 (aka SQL 3) whenever SQL-92 is not sufficient. All ECSQL examples in the following sections refer to classes and relationships from the BisCore ECSchema (unless mentioned otherwise). Fully qualifying ECClasses in ECSQL The classes used in an ECSQL have to be fully qualified by their schemas. Syntax: <Schema name or alias>.<Class name> Instead of '.' you can also use ':' as delimiter between schema and class name. Example The following examples are equivalent. This one uses the schema name: SELECT Model, CodeValue, Parent FROM BisCore.Element And this one uses the schema alias: SELECT Model, CodeValue, Parent FROM bis.Element ECSQL Parameters To bind values to an ECSQL statement after preparation, the following parameter placeholders are supported. Parameter type Description ? Positional parameter. Its index is one greater than the previous parameter in the ECSQL statement. :aaa Named parameter. This allows to bind the same value to more than one placeholder. Example SELECT ECInstanceId FROM bis.GeometricElement3d WHERE Model=? AND LastMod>=? SELECT ECInstanceId FROM bis.GeometricElement3d LIMIT :pagesize OFFSET (:pageno * :pagesize) See also sections ECInstanceId and ECClassId and LIMIT and OFFSET. ECInstanceId and ECClassId ECSQL defines a set of built-in system properties. They don't have to be defined in the ECSchemas. Property Description ECInstanceId Is the unique identifier for an ECInstance. ECClassId Refers to the ECClassId of an ECClass. It uniquely identifies an ECClass in the iModel. In iTwin.js the ECClassId is formatted as fully qualified class name when used in the SELECT clause. Example SELECT Parent, ECClassId FROM bis.Element WHERE ECInstanceId=123 Basic data types in ECSQL ECSQL supports all primitive types built into EC. This means that in addition to the basic numeric and string data types in SQL-92, ECSQL also supports boolean, BLOBs, date-times and points. Boolean For Boolean types ECSQL supports the literals True and False. Examples SELECT ECInstanceId, Model, CodeValue FROM bis.ViewDefinition3d WHERE IsCameraOn = True SELECT ECInstanceId, Model, CodeValue FROM bis.ViewDefinition3d WHERE IsCameraOn = False Boolean properties or expressions do not need to be compared to True and False as they return a boolean value already. So the above examples can also be written like this: SELECT ECInstanceId, Model, CodeValue FROM bis.ViewDefinition3d WHERE IsCameraOn SELECT ECInstanceId, Model, CodeValue FROM bis.ViewDefinition3d WHERE NOT IsCameraOn DateTime ECSQL supports dates without time (DATE), dates with time (TIMESTAMP), and times without date (TIME). ECSQL does not support time zone conversions. Time zone conversions are to be handled by the application. Literals DATE 'yyyy-mm-dd' TIMESTAMP 'yyyy-mm-dd hh:mm:ss[.nnn][Z]' TIME 'hh:mm:ss[.nnn]' The time stamp format matches the ISO 8601 standard (see also https://en.wikipedia.org/wiki/ISO_8601) Basic functions Function Description CURRENT_DATE returns the current date CURRENT_TIMESTAMP returns the current timestamp in UTC. CURRENT_TIME returns the current time of the day. Example SELECT ECInstanceId, Model, CodeValue FROM bis.Element WHERE LastMod > DATE '2018-01-01' SELECT ECInstanceId, Model, CodeValue FROM bis.Element WHERE LastMod < TIMESTAMP '2017-07-15T12:00:00.000Z'` SELECT ECInstanceId, Model, CodeValue FROM bis.Element WHERE LastMod BETWEEN :startperiod AND :endperiod` SELECT ECInstanceId FROM myschema.CalenderEntry WHERE startTime >= TIME '08:30:00' AND startTime <= TIME '09:00:00' The last example is based on this ECSchema snippet: <ECEntityClass typeName="CalenderEntry"> <ECProperty propertyName="startTime" typeName="dateTime"> <ECCustomAttributes> <DateTimeInfo xmlns="CoreCustomAttributes.01.00.01"> <DateTimeComponent>TimeOfDay</DateTimeComponent> </DateTimeInfo> </ECCustomAttributes> </ECProperty> <ECProperty propertyName="endTime" typeName="dateTime"> <ECCustomAttributes> <DateTimeInfo xmlns="CoreCustomAttributes.01.00.01"> <DateTimeComponent>TimeOfDay</DateTimeComponent> </DateTimeInfo> </ECCustomAttributes> </ECProperty> </ECEntityClass> Points Points are a built-in primitive type in ECSchemas and are therefore supported in ECSQL. In the context of ECSQL Point ECProperties are interpreted as structs made up of the following system properties: Property Description X X coordinate of the Point2d or Point3d Y Y coordinate of the Point2d or Point3d Z Z coordinate of the Point3d Example SELECT ECInstanceId, Model, CodeValue FROM bis.GeometricElement3d WHERE Origin.X BETWEEN 3500000.0 AND 3500500.0 AND Origin.Y BETWEEN 5700000.0 AND 5710000.0 AND Origin.Z BETWEEN 0 AND 100.0 Structs In ECSQL you can refer to a struct ECProperty either as a whole or by just referring to some of its members. The operator for referencing members of structs in an ECSQL is the '.'. Examples ECSQL Description SELECT Location FROM myschema.Company WHERE Name='ACME' Returns the Location struct property as a whole SELECT Name,Location.Street,Location.City FROM myschema.Company WHERE ECInstanceId=? Returns the Street and City members of the Location struct property SELECT Name FROM myschema.Company WHERE Location=? Returns rows that match the bound Location value. The Location must be bound as a whole. SELECT Name FROM myschema.Company WHERE Location.Zip=12314 Returns rows that match the Location's Zip member value based on this ECSchema snippet: <ECStructClass typeName="Address"> <ECProperty propertyName="Street" typeName="string" /> <ECProperty propertyName="City" typeName="string" /> <ECProperty propertyName="Zip" typeName="int" /> </ECStructClass> <ECEntityClass typeName="Company"> <ECProperty propertyName="Name" typeName="string" /> <ECArrayProperty propertyName="Location" typeName="Address" /> </ECEntityClass> Arrays In ECSQL you can refer to Array ECProperties only as a whole. Examples ECSQL Description SELECT PhoneNumbers FROM myschema.Company WHERE Name='ACME' Returns the PhoneNumbers array of the ACME company SELECT Name FROM myschema.Company WHERE PhoneNumbers=? Returns the companies that match the bound PhoneNumber array. The array must be bound as a whole. based on this ECSchema snippet: <ECEntityClass typeName="Company"> <ECProperty propertyName="Name" typeName="string" /> <ECArrayProperty propertyName="PhoneNumbers" typeName="string" /> </ECEntityClass> Navigation Properties Navigation properties are ECProperties that point to a related object. They are always backed by an ECRelationshipClass. In the context of ECSQL navigation properties are interpreted as structs made up of the following system properties: Property Description Id ECInstanceId of the related instance RelECClassId ECClassId of the ECRelationshipClass backing the navigation property. It is mainly relevant when the ECRelationshipClass has subclasses. Navigation properties are a convenient short-cut for ECSQL Joins. See also ECRelationshipClasses. Examples ECSQL Description SELECT Parent FROM bis.Element WHERE ECInstanceId=? Returns the Parent navigation property as a whole (including Id and RelECClassId) SELECT Parent.Id FROM bis.Element WHERE ECInstanceId=? Returns just the Id member of the Parent navigation property SELECT Parent.Id, Parent.RelECClassId FROM bis.Element WHERE ECInstanceId=? Returns the Id, and the RelECClassId member of the Parent navigation property as two separate columns ECRelationshipClasses As ECRelationshipClasses are ECClasses as well, they can be used in ECSQL like ECClasses. Their additional relationship semantics is expressed by these system properties. Property Description SourceECInstanceId ECInstanceId of the instance on the source end of the relationship SourceECClassId ECClassId of the instance on the source end of the relationship TargetECInstanceId ECInstanceId of the instance on the target end of the relationship TargetECClassId ECClassId of the instance on the target end of the relationship If the ECRelationshipClass is backed by a Navigation property, it is usually much easier to use the navigation property in your ECSQL than the ECRelationshipClass. SourceECClassId and TargetECClassId are skipped when performing a SELECT * FROM statement or an INSERT INTO statement without a property name list. Examples ECSQL Description SELECT SourceECInstanceId FROM bis.ElementDrivesElement WHERE TargetECInstanceId=? AND Status=? Returns the ECInstanceId of all Elements that drive the Element bound to the first parameter SELECT TargetECInstanceId,TargetECClassId FROM bis.ModelHasElements WHERE SourceECInstanceId=? Returns the ECInstanceId and ECClassId of all Elements contained by the Model bound to the parameter Joins Joins between ECClasses are specified with the standard SQL join syntax (either JOIN ... ON ... or the theta style). In ECSchemas ECRelationshipClasses are used to relate two ECClasses. ECRelationshipClasses can therefore be seen as virtual link tables between those two classes. If you want to join two ECClasses via their ECRelationshipClass, you need to join the first class to the relationship class and then the relationship class to the second class. If navigation properties are defined for the ECRelationship class, use the navigation property instead of a join. Examples Without navigation property (2 JOINs needed): SELECT e.CodeValue,e.UserLabel FROM bis.Element driver JOIN bis.ElementDrivesElement ede ON driver.ECInstanceId=ede.SourceECInstanceId JOIN bis.Element driven ON driven.ECInstanceId=ede.TargetECInstanceId WHERE driven.ECInstanceId=? AND ede.Status=? With navigation property (Element.Model): Return the CodeValue and UserLabel of all Elements in the Model with the specified condition (1 JOIN needed): SELECT e.CodeValue,e.UserLabel FROM bis.Element e JOIN bis.Model m ON e.Model.Id=m.ECInstanceId WHERE m.Name=? Return the Model for an Element with the specified condition (No join needed): SELECT Model FROM bis.Element WHERE ECInstanceId=? Polymorphic Queries By default, any ECClass in the FROM clause of an ECSQL is treated polymorphically, i.e. all its subclasses are considered as well. If an ECClass should be treated non-polymorphically, i.e. only the class itself and not its subclasses should be considered, add the ONLY keyword in front of it. This also applies to Mixins. Mixins technically are ECClasses (abstract Entity ECClasses to be precise). So you can simply query against a mixin class without knowing which classes actually implement the mixin. Examples ECSQL Description `SELECT ECInstanceId FROM bis.Element WHERE Model=?`` Returns all Elements of any subclass in the specified Model `SELECT ECInstanceId FROM bis.SpatialViewDefinition WHERE ModelSelector=?`` Returns SpatialViewDefinitions rows and rows of its subclasses for the specified ModelSelector `SELECT ECInstanceId FROM ONLY bis.SpatialViewDefinition WHERE ModelSelector=?`` Returns only SpatialViewDefinitions rows for the specified ModelSelect, but no rows from its subclasses. LIMIT and OFFSET One way to implement paging is to use the LIMIT and OFFSET clauses in ECSQL. The LIMIT clause is used to limit the number of results returned from an ECSQL statement. Using LIMIT together with OFFSET allows specifying a range of rows to be returned. The OFFSET hereby specifies how many rows will be omitted from the result set. The LIMIT specifies the number of rows to be returned. Examples Return only the first 50 matching Elements: SELECT ECInstanceId,CodeValue,Parent FROM BisCore.Element WHERE Model=? LIMIT 50 Return the 201st through 250th matching Element: SELECT ECInstanceId,CodeValue,Parent FROM BisCore.Element WHERE Model=? LIMIT 50 OFFSET 200 SQL Functions SQL functions, either built into SQLite or custom SQL functions, can be used in ECSQL. Examples SELECT substr(CodeValue,1,5) FROM bis.Element WHERE Model=?` SELECT ECInstanceId FROM bis.Element WHERE lower(UserLabel)=?` See also SQLite Functions overview. Spatial Queries and Geometry Functions ECSQL can perform spatial queries. ECSQL has a number of built-in geometry functions Common Table Expressions ECSQL can do regular and recursive CTE queries Last Updated: 02 February, 2022