How Entity SQL differs from Transact-SQL
This article describes the differences between Entity SQL and Transact-SQL.
Inheritance and Relationships Support
Entity SQL works directly with conceptual entity schemas and supports conceptual model features such as inheritance and relationships.
When working with inheritance, it is often useful to select instances of a subtype from a collection of supertype instances. The oftype operator in Entity SQL (similar to oftype
in C# Sequences) provides this capability.
Support for Collections
Entity SQL treats collections as first-class entities. For example:
Collection expressions are valid in a
from
clause.in
andexists
subqueries have been generalized to allow any collections.A subquery is one kind of collection.
e1 in e2
andexists(e)
are the Entity SQL constructs to perform these operations.Set operations, such as
union
,intersect
, andexcept
, now operate on collections.Joins operate on collections.
Support for Expressions
Transact-SQL has subqueries (tables) and expressions (rows and columns).
To support collections and nested collections, Entity SQL makes everything an expression. Entity SQL is more composable than Transact-SQL—every expression can be used anywhere. Query expressions always result in collections of the projected types and can be used anywhere a collection expression is allowed. For information about Transact-SQL expressions that are not supported in Entity SQL, see Unsupported Expressions.
The following are all valid Entity SQL queries:
1+2 *3
"abc"
row(1 as a, 2 as b)
{ 1, 3, 5}
e1 union all e2
set(e1)
Uniform Treatment of Subqueries
Given its emphasis on tables, Transact-SQL performs contextual interpretation of subqueries. For example, a subquery in the from
clause is considered to be a multiset (table). But the same subquery used in the select
clause is considered to be a scalar subquery. Similarly, a subquery used on the left side of an in
operator is considered to be a scalar subquery, while the right side is expected to be a multiset subquery.
Entity SQL eliminates these differences. An expression has a uniform interpretation that does not depend on the context in which it is used. Entity SQL considers all subqueries to be multiset subqueries. If a scalar value is desired from the subquery, Entity SQL provides the anyelement
operator that operates on a collection (in this case, the subquery), and extracts a singleton value from the collection.
Avoiding Implicit Coercions for Subqueries
A related side effect of uniform treatment of subqueries is implicit conversion of subqueries to scalar values. Specifically, in Transact-SQL, a multiset of rows (with a single field) is implicitly converted into a scalar value whose data type is that of the field.
Entity SQL does not support this implicit coercion. Entity SQL provides the ANYELEMENT
operator to extract a singleton value from a collection, and a select value
clause to avoid creating a row-wrapper during a query expression.
Select Value: Avoiding the Implicit Row Wrapper
The select clause in a Transact-SQL subquery implicitly creates a row wrapper around the items in the clause. This implies that we cannot create collections of scalars or objects. Transact-SQL allows an implicit coercion between a rowtype
with one field and a singleton value of the same data type.
Entity SQL provides the select value
clause to skip the implicit row construction. Only one item may be specified in a select value
clause. When such a clause is used, no row wrapper is constructed around the items in the select
clause, and a collection of the desired shape may be produced, for example, select value a
.
Entity SQL also provides the row constructor to construct arbitrary rows. select
takes one or more elements in the projection and results in a data record with fields:
select a, b, c
Left Correlation and Aliasing
In Transact-SQL, expressions in a given scope (a single clause like select
or from
) cannot reference expressions defined earlier in the same scope. Some dialects of SQL (including Transact-SQL) do support limited forms of these in the from
clause.
Entity SQL generalizes left correlations in the from
clause, and treats them uniformly. Expressions in the from
clause can reference earlier definitions (definitions to the left) in the same clause without the need for additional syntax.
Entity SQL also imposes additional restrictions on queries involving group by
clauses. Expressions in the select
clause and having
clause of such queries may only refer to the group by
keys via their aliases. The following construct is valid in Transact-SQL but are not in Entity SQL:
SELECT t.x + t.y FROM T AS t group BY t.x + t.y
To do this in Entity SQL:
SELECT k FROM T AS t GROUP BY (t.x + t.y) AS k
Referencing Columns (Properties) of Tables (Collections)
All column references in Entity SQL must be qualified with the table alias. The following construct (assuming that a
is a valid column of table T
) is valid in Transact-SQL but not in Entity SQL.
SELECT a FROM T
The Entity SQL form is
SELECT t.a AS A FROM T AS t
The table aliases are optional in the from
clause. The name of the table is used as the implicit alias. Entity SQL allows the following form as well:
SELECT Tab.a FROM Tab
Navigation Through Objects
Transact-SQL uses the "." notation for referencing columns of (a row of) a table. Entity SQL extends this notation (borrowed from programming languages) to support navigation through properties of an object.
For example, if p
is an expression of type Person, the following is the Entity SQL syntax for referencing the city of the address of this person.
p.Address.City
No Support for *
Transact-SQL supports the unqualified * syntax as an alias for the entire row, and the qualified * syntax (t.*) as a shortcut for the fields of that table. In addition, Transact-SQL allows for a special count(*) aggregate, which includes nulls.
Entity SQL does not support the * construct. Transact-SQL queries of the form select * from T
and select T1.* from T1, T2...
can be expressed in Entity SQL as select value t from T as t
and select value t1 from T1 as t1, T2 as t2...
, respectively. Additionally, these constructs handle inheritance (value substitutability), while the select *
variants are restricted to top-level properties of the declared type.
Entity SQL does not support the count(*)
aggregate. Use count(0)
instead.
Changes to Group By
Entity SQL supports aliasing of group by
keys. Expressions in the select
clause and having
clause must refer to the group by
keys via these aliases. For example, this Entity SQL syntax:
SELECT k1, count(t.a), sum(t.a)
FROM T AS t
GROUP BY t.b + t.c AS k1
...is equivalent to the following Transact-SQL:
SELECT b + c, count(*), sum(a)
FROM T
GROUP BY b + c
Collection-Based Aggregates
Entity SQL supports two kinds of aggregates.
Collection-based aggregates operate on collections and produce the aggregated result. These can appear anywhere in the query, and do not require a group by
clause. For example:
SELECT t.a AS a, count({1,2,3}) AS b FROM T AS t
Entity SQL also supports SQL-style aggregates. For example:
SELECT a, sum(t.b) FROM T AS t GROUP BY t.a AS a
ORDER BY Clause Usage
Transact-SQL allows ORDER BY
clauses to be specified only in the topmost SELECT .. FROM .. WHERE
block. In Entity SQL, you can use a nested ORDER BY
expression and it can be placed anywhere in the query, but ordering in a nested query is not preserved.
-- The following query will order the results by the last name
SELECT C1.FirstName, C1.LastName
FROM AdventureWorks.Contact AS C1
ORDER BY C1.LastName
-- In the following query ordering of the nested query is ignored.
SELECT C2.FirstName, C2.LastName
FROM (SELECT C1.FirstName, C1.LastName
FROM AdventureWorks.Contact as C1
ORDER BY C1.LastName) as C2
Identifiers
In Transact-SQL, identifier comparison is based on the collation of the current database. In Entity SQL, identifiers are always case insensitive and accent sensitive (that is, Entity SQL distinguishes between accented and unaccented characters; for example, 'a' is not equal to 'ấ'). Entity SQL treats versions of letters that appear the same but are from different code pages as different characters. For more information, see Input Character Set.
Transact-SQL Functionality Not Available in Entity SQL
The following Transact-SQL functionality is not available in Entity SQL.
DML
Entity SQL currently provides no support for DML statements (insert, update, delete).
DDL
Entity SQL provides no support for DDL in the current version.
Imperative Programming
Entity SQL provides no support for imperative programming, unlike Transact-SQL. Use a programming language instead.
Grouping Functions
Entity SQL does not yet provide support for grouping functions (for example, CUBE, ROLLUP, and GROUPING_SET).
Analytic Functions
Entity SQL does not (yet) provide support for analytic functions.
Built-in Functions, Operators
Entity SQL supports a subset of Transact-SQL's built in functions and operators. These operators and functions are likely to be supported by the major store providers. Entity SQL uses the store-specific functions declared in a provider manifest. Additionally, the Entity Framework allows you to declare built-in and user-defined existing store functions, for Entity SQL to use.
Hints
Entity SQL does not provide mechanisms for query hints.
Batching Query Results
Entity SQL does not support batching query results. For example, the following is valid Transact-SQL (sending as a batch):
SELECT * FROM products;
SELECT * FROM categories;
However, the equivalent Entity SQL is not supported:
SELECT value p FROM Products AS p;
SELECT value c FROM Categories AS c;
Entity SQL only supports one result-producing query statement per command.